Results 1 to 10 of 10

Thread: [RESOLVED] No WPF masked textbox??? Really???

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Mar 2008
    Location
    Burlington, ON, Canada
    Posts
    343

    Resolved [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

  2. #2

    Thread Starter
    Hyperactive Member
    Join Date
    Mar 2008
    Location
    Burlington, ON, Canada
    Posts
    343

    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.

  3. #3
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    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
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  4. #4

    Thread Starter
    Hyperactive Member
    Join Date
    Mar 2008
    Location
    Burlington, ON, Canada
    Posts
    343

    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

  5. #5

    Thread Starter
    Hyperactive Member
    Join Date
    Mar 2008
    Location
    Burlington, ON, Canada
    Posts
    343

    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.

  6. #6

    Thread Starter
    Hyperactive Member
    Join Date
    Mar 2008
    Location
    Burlington, ON, Canada
    Posts
    343

    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?.....

  7. #7
    Lively Member
    Join Date
    Jul 2007
    Posts
    127

    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.

  8. #8

    Thread Starter
    Hyperactive Member
    Join Date
    Mar 2008
    Location
    Burlington, ON, Canada
    Posts
    343

    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.

  9. #9

    Thread Starter
    Hyperactive Member
    Join Date
    Mar 2008
    Location
    Burlington, ON, Canada
    Posts
    343

    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

  10. #10
    New Member
    Join Date
    Mar 2012
    Posts
    1

    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
  •  



Click Here to Expand Forum to Full Width