I needed to Limit several TextBoxes in my WPF MVVM application to only allow Numeric Characters.
I stumbles upon a very useful post by Jermey Likeness which described a method using Attached Behaviours, which worked well for me;
http://csharperimage.jeremylikness.com/2009/10/silverlight-behaviors-and-triggers_07.html
I modified this code slightly to allow for Decimal point control also.
The VB.net Code is as follows;
Imports System.Collections.ObjectModel
Namespace Behaviours
Public Class clsTextBoxFilters
#Region "Variables"
Private Shared ReadOnly _controlKeys As List(Of Key) = New List(Of Key) From {Key.Back,
Key.CapsLock,
Key.LeftCtrl,
Key.RightCtrl,
Key.Down,
Key.[End],
Key.Enter,
Key.Escape,
Key.Home,
Key.Insert,
Key.Left,
Key.PageDown,
Key.PageUp,
Key.Right,
Key.LeftShift,
Key.RightShift,
Key.Tab,
Key.Up,
Key.Decimal,
Key.OemPeriod}
#End Region
#Region "Helper Functions"
''' <summary>
''' Check if the key is a Numeric
''' </summary>
''' <param name="key__1"></param>
''' <returns></returns>
''' <remarks></remarks>
Private Shared Function _IsDigit(key__1 As Key) As Boolean
Dim shiftKey As Boolean = (Keyboard.Modifiers And ModifierKeys.Shift) <> 0
Dim retVal As Boolean
If key__1 >= Key.D0 AndAlso key__1 <= Key.D9 AndAlso Not shiftKey Then
retVal = True
Else
retVal = key__1 >= Key.NumPad0 AndAlso key__1 <= Key.NumPad9
End If
Return retVal
End Function
#End Region
#Region "Getters and Setters"
''' <summary>
''' Get the value of the Numeric Filter Dependancy Property
''' </summary>
''' <param name="src"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function GetIsPositiveNumericFilter(src As DependencyObject) As Boolean
Return CBool(src.GetValue(IsPositiveNumericFilterProperty))
End Function
''' <summary>
''' Set the Value of the Numeric Filter Dependancy Property
''' </summary>
''' <param name="src"></param>
''' <param name="value"></param>
''' <remarks></remarks>
Public Shared Sub SetIsPositiveNumericFilter(src As DependencyObject, value As Boolean)
src.SetValue(IsPositiveNumericFilterProperty, value)
End Sub
''' <summary>
''' Get the Value of the IsIntegerOnly Dependancy Property
''' </summary>
''' <param name="src"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function GetIsIntegerOnly(src As DependencyObject) As Boolean
Return CBool(src.GetValue(IsIntegerOnlyProperty))
End Function
''' <summary>
''' Sets the Value of the IsIntegerOnly Dependancy Property
''' </summary>
''' <param name="src"></param>
''' <param name="value"></param>
''' <remarks></remarks>
Public Shared Sub SetIsIntegerOnly(src As DependencyObject, value As Boolean)
src.SetValue(IsIntegerOnlyProperty, value)
End Sub
#End Region
#Region "Dependancy Properties"
Public Shared IsPositiveNumericFilterProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsPositiveNumericFilter", GetType(Boolean), GetType(clsTextBoxFilters), New PropertyMetadata(False, AddressOf IsPositiveNumericFilterChanged))
Public Shared IsIntegerOnlyProperty As DependencyProperty = DependencyProperty.Register("IsIntegerOnly", GetType(Boolean), GetType(clsTextBoxFilters), Nothing)
#End Region
#Region "Dependancy Property Change Handlers"
''' <summary>
''' Determines if the Behaviour is active, adds the KeyDown event Handler
''' </summary>
''' <param name="src"></param>
''' <param name="args"></param>
''' <remarks></remarks>
Public Shared Sub IsPositiveNumericFilterChanged(src As DependencyObject, args As DependencyPropertyChangedEventArgs)
If src IsNot Nothing AndAlso TypeOf src Is TextBox Then
Dim textBox As TextBox = TryCast(src, TextBox)
If CBool(args.NewValue) Then
AddHandler textBox.KeyDown, AddressOf _TextBoxPositiveNumericKeyDown
End If
End If
End Sub
#End Region
#Region "Event Handlers"
''' <summary>
''' KeyDown event... Check if the Key is valid... If so allow, if not then ignore the key
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Shared Sub _TextBoxPositiveNumericKeyDown(sender As Object, e As KeyEventArgs)
Dim handled As Boolean = True
Dim txtSender As TextBox = DirectCast(sender, TextBox)
If e.Key = Key.OemPeriod Then 'Is the current key a Decimal Point?
If txtSender.GetValue(IsIntegerOnlyProperty) = True Then 'Is this an Integer Only TextBox?
handled = True
ElseIf InStr(txtSender.Text, ".") = 0 And Len(txtSender.Text) > 0 Then 'We only want 1 decimal point, and it can't be the first digit!
handled = False
Else 'Otherwise ignore the keypress
handled = True
End If
ElseIf _controlKeys.Contains(e.Key) OrElse _IsDigit(e.Key) Then 'Is the Key a numeric or an allowed key?
handled = False
End If
e.Handled = handled
End Sub
#End Region
End Class
End Namespace
The XAML to add to the UserControl Header Namespaces is;
xmlns:Behaviors="clr-namespace:CriticalPath_WPF_MVVM_EF.Behaviours"
The XAML to add to the TextBox Is;
Behaviors:clsTextBoxFilters.IsPositiveNumericFilter="True" Behaviors:clsTextBoxFilters.IsIntegerOnly="True"
Very handy!
No comments:
Post a Comment