-
Oct 26th, 2010, 06:04 PM
#1
Thread Starter
Hyperactive Member
[RESOLVED] No WPF masked textbox??? Really???
this is the most basic of the basic in my opinion and should have been included loooong ago in WPF, that's crazy.....so on to the question:
aside from 3rd party controls, or hosting a winforms container - does anybody have either xaml or codebehind (or both) to do a simple north american telephone number masked textbox in VB2010? format of (999) 999-9999
as usual, i'm all ears and if i find something sooner i'll post it here - suggestions are DEFINITELY welcome on this one....
Thx
-
Oct 27th, 2010, 08:45 PM
#2
Thread Starter
Hyperactive Member
Re: No WPF masked textbox??? Really???
so at this point i'm going to try and duplicate the behavior specifically for a "mask" of north american telephone numbers as you type and would love any contributions anybody has - for starters I've restricted the allowable characters entered in to the text box as 0 thru 9, an open bracket, a closed bracket, a space, and a dash in previewtextinput (the duplication attempt is from a winforms masked textbox called mtbphone but now being used in WPF that doesn't have a maskedtextbox control):
Code:
Private Sub mtbPhone_PreviewTextInput(ByVal sender As Object, ByVal e As System.Windows.Input.TextCompositionEventArgs) Handles mtbPhone.PreviewTextInput
Dim allowedchars As String = "0123456789()- "
If allowedchars.IndexOf(CChar(e.Text)) = -1 Then e.Handled = True
End Sub
so how do i allow only a single right bracket, a single left bracket, a single dash, and a single space yet allow unlimited numbers in WPF? (i"ve restricted the length of the textbox to 14 for the (999) 999-9999 format) - right now you can type 14 right brackets if you want and fill the textbox.
in moving forward with this, if i can figure that out, i'd like to capture keystrokes at each of the 14 positions of the textbox and insert the mask accordingly.....suggestions are welcome guys.....and absolutely requested at this point.... :-)
Last edited by trevorjeaton; Oct 27th, 2010 at 09:03 PM.
-
Oct 27th, 2010, 11:05 PM
#3
Re: No WPF masked textbox??? Really???
How about only allowing them to enter numbers only, and then using the string.format method to format the number using "(###) ###-####" as the format?
-tg
-
Oct 28th, 2010, 11:46 AM
#4
Thread Starter
Hyperactive Member
Re: No WPF masked textbox??? Really???
here's the new code but the string format isn't firing - numeric only input is working though:
Code:
Private Sub mtbPhone_PreviewTextInput(ByVal sender As Object, ByVal e As System.Windows.Input.TextCompositionEventArgs) Handles mtbPhone.PreviewTextInput
Dim allowedchars As String = "0123456789"
If allowedchars.IndexOf(CChar(e.Text)) = -1 Then e.Handled = True
mtbPhone.Text = String.Format("{0:(###) ###-####}", mtbPhone.Text)
End Sub
-
Oct 28th, 2010, 11:54 AM
#5
Thread Starter
Hyperactive Member
Re: No WPF masked textbox??? Really???
okay, this works on the mtbphone_LostFocus event if 10 digits are typed in and the user tabs out of the control - eg. 1234567890 gets reformatted to (123) 456-7890:
Code:
Private Sub mtbPhone_LostFocus(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles mtbPhone.LostFocus
mtbPhone.Text = String.Format("({0}) {1}-{2}", mtbPhone.Text.Substring(0, 3), mtbPhone.Text.Substring(3, 3), mtbPhone.Text.Substring(6))
End Sub
but how can i do the above "as you type"? obviously the substring positions in the above code do not exist yet if the user is only typing in digit number 2 at the moment for example.....
Last edited by trevorjeaton; Oct 28th, 2010 at 12:53 PM.
-
Oct 28th, 2010, 12:18 PM
#6
Thread Starter
Hyperactive Member
Re: No WPF masked textbox??? Really???
could i determine the position of the caret or the mtb.text.length and do a select case scenario?.....
-
Oct 29th, 2010, 09:41 AM
#7
Lively Member
Re: No WPF masked textbox??? Really???
y not just have 3 separate text boxes? you can easily make them numeric only, allow only 3 or 4 characters per, and switch focus after the user enters the 3 or 4 digits.
-
Nov 9th, 2010, 09:24 AM
#8
Thread Starter
Hyperactive Member
Re: No WPF masked textbox??? Really???
okay this one was fun, and is not only corrected as a north american phone number mask, but as a fully masked textbox for wpf - my hat goes off to matthew macdonald and his apress book "Pro WPF with VB 2008" - i used vb 2010 in this case and had the same results.
Here's what you do:
- right-click your project and select add, then class
- call the class MaskedTextBox.vb
- add the imports statement at the very top
Code:
Imports System.ComponentModel
- paste the following code between 'Public Class MaskedTextBox' and 'End Class'
Code:
Inherits System.Windows.Controls.TextBox
Public Shared maskproperty As DependencyProperty
Shared Sub New()
maskproperty = DependencyProperty.Register("Mask", GetType(String), GetType(MaskedTextBox), New FrameworkPropertyMetadata(AddressOf maskchanged))
Dim metadata As New FrameworkPropertyMetadata()
metadata.CoerceValueCallback = AddressOf coercetext
TextProperty.OverrideMetadata(GetType(MaskedTextBox), metadata)
End Sub
Private Shared Function coercetext(ByVal d As DependencyObject, ByVal value As Object)
Dim textbox As MaskedTextBox = CType(d, MaskedTextBox)
Dim maskprovider As New MaskedTextProvider(textbox.Mask)
maskprovider.Set(CStr(value))
Return maskprovider.ToDisplayString()
End Function
Public Property Mask() As String
Get
Return CStr(GetValue(maskproperty))
End Get
Set(ByVal value As String)
SetValue(maskproperty, value)
End Set
End Property
Private Function getmaskprovider() As MaskedTextProvider
Dim maskprovider As New MaskedTextProvider(Mask)
maskprovider.Set(Text)
Return maskprovider
End Function
Private Sub refreshtext(ByVal maskprovider As MaskedTextProvider, ByVal pos As Integer)
Me.Text = maskprovider.ToDisplayString()
Me.SelectionStart = pos
End Sub
Public ReadOnly Property maskcompleted() As Boolean
Get
Dim maskprovider As MaskedTextProvider = getmaskprovider()
Return maskprovider.MaskCompleted
End Get
End Property
Private Shared Sub maskchanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
Dim textbox As MaskedTextBox = CType(d, MaskedTextBox)
d.CoerceValue(TextProperty)
Dim maskprovider As MaskedTextProvider = textbox.getmaskprovider()
textbox.refreshtext(maskprovider, 0)
End Sub
Private Function skiptoeditablecharacter(ByVal startpos As Integer) As Integer
Dim maskprovider As MaskedTextProvider = getmaskprovider()
Dim newpos As Integer = maskprovider.FindEditPositionFrom(startpos, True)
If newpos = -1 Then
Return startpos
Else
Return newpos
End If
End Function
Protected Overrides Sub OnPreviewTextInput(ByVal e As System.Windows.Input.TextCompositionEventArgs)
Dim maskprovider As MaskedTextProvider = getmaskprovider()
Dim pos As Integer = Me.SelectionStart
'Adding a character
If pos < Me.Text.Length Then
pos = skiptoeditablecharacter(pos)
'Overwrite mode is on.
If Keyboard.IsKeyToggled(Key.Insert) Then
If maskprovider.Replace(e.Text, pos) Then
pos += 1
End If
' insert mode is on
Else
If maskprovider.InsertAt(e.Text, pos) Then
pos += 1
End If
End If
'find the new cursor position
pos = skiptoeditablecharacter(pos)
End If
refreshtext(maskprovider, pos)
e.Handled = True
MyBase.OnPreviewTextInput(e)
End Sub
Protected Overrides Sub OnPreviewKeyDown(ByVal e As System.Windows.Input.KeyEventArgs)
MyBase.OnKeyDown(e)
Dim maskprovider As MaskedTextProvider = getmaskprovider()
Dim pos As Integer = Me.SelectionStart
'deleteing a character (delete key)
' this does nothing if you try to delete a format character
If e.Key = Key.Delete AndAlso pos < (Me.Text.Length) Then
If maskprovider.RemoveAt(pos) Then
refreshtext(maskprovider, pos)
End If
e.Handled = True
'deleting a character (backspace)
' this steps over a format character, but doesn't delete the next character
ElseIf e.Key = Key.Back Then
If pos > 0 Then
pos -= 1
If maskprovider.RemoveAt(pos) Then
refreshtext(maskprovider, pos)
End If
End If
e.Handled = True
End If
End Sub
Public Sub New()
MyBase.New()
Dim commandbinding1 As New CommandBinding(ApplicationCommands.Paste, Nothing, AddressOf suppresscommand)
Me.CommandBindings.Add(commandbinding1)
Dim commandbinding2 As New CommandBinding(ApplicationCommands.Cut, Nothing, AddressOf suppresscommand)
Me.CommandBindings.Add(commandbinding2)
End Sub
Private Sub suppresscommand(ByVal sender As Object, ByVal e As CanExecuteRoutedEventArgs)
e.CanExecute = False
e.Handled = True
End Sub
- Build your project
you should now have MaskedTextBox in your toolbox - drag and drop it on to your window.
- under the properties of the control, open up the 'Other' subcategory (if it isn't already) and find the 'Mask' property
- enter your mask - in my case it was (999) 999-9999
- for other masks, use the following characters:
0 = required digit
9 = optional digit or space, if left blank, a space is inserted automatically
# = optional digit, space, or plus/minus symbol. if left blank, a space is inserted automatically
L = required ascii letter (a-z or A-Z)
? = optional ascii letter
& = required unicode character. allows anything that isn't a control key, including punctuation and symbols
C = optional unicode character
A = required alphanumeric character (allows letter or number but not punctuation or symbols)
a = optional alphanumeric character
. = decimal placeholder
, = thousands placeholder
: = time separator
/ = date separator
$ = currency symbol
< = all the characters that follow will be converted automatically to lowercase as the user types them. (there is no way to switch back to mixed-case entry mode once you use this character)
> = all the characters that follow will be converted automatically to uppercase as the user types them
\ = escapes a masked character, turning it in to a literal. thus, if you use \&, it is interpreted as the literal character &, which will be inserted in to the text box
All other characters = All other characters are treated as literals and are shown in the text box.
- as an example, an ip address mask would be 990.990.990.990
- a north american phone number would be (999) 999-9999
- etc etc etc
Hopefully this will save others the vast amount of time i had to spend on a trivial item like this, however, i'm glad its resolved because i'll be using this class a million times over i'm sure, or at least until wpf 5 (or silverlight 5) contains a native masked textbox..... :-)
thanks to TG and bflosabre91 for their input, it was invaluable in moving forward on this one.
Enjoy!!!
Last edited by trevorjeaton; Nov 23rd, 2010 at 10:09 PM.
-
Nov 11th, 2010, 08:48 AM
#9
Thread Starter
Hyperactive Member
Re: [RESOLVED] No WPF masked textbox??? Really???
correction to my mask example above - for a phone number the digits are required digits so it would actually be (000) 000-0000
-
Mar 20th, 2012, 11:25 AM
#10
New Member
Re: [RESOLVED] No WPF masked textbox??? Really???
I know this is a 2yr old thread, but I was wondering how I can set the content of a masked textbox, in the code-behind?
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|