Masking input to a WPF TextBox
How do you go about masking the input to a textbox. Say you wanted to allow numbers but not letters or any punctuation, how would you do it? Well the simplest way is to trap the TextChanged event… This method is simple to understand (always a positive) but there are a few problems with this as I see it, namely.. This is not a great way to solve the original problem, because we’re basically hacking at the input after it’s already been accepted. Leaving us trying to fix the text and compensate for the changes in caret position. It’s easier to reject invalid characters as they’re presented. Let’s start by defining a very simple method for stripping out the input we don’t want.. This could be defined slightly more elegantly using a predicate.. We then need to identify the entry points to the control and for each one, identify how we will be notified about it’s use. For typical a TextBox these entry points might be: It’s easy to implement and hook up the handlers for these events.. In some cases, you may need to support other scenarios (such as allowing users to Drag-and-Drop text onto it) and these can be dealt with in a similar fashion – identify an appropriate event, check the input, and if it’s invalid then prevent any further processing. I hope this information serves as a starting point for implementing a masked textbox. That is, display an actual mask (using underlines) and rigidly control the input of the user. one immediate change is that you’d look to subclass TextBox (or base class) and override the protected handlers (e.g. onPreviewTextInput) rather than hook up directly to the events. The underlines are also important because without them the user has little clue what is expected of them. Infact, in a basic validation scenario I think it better to accept dodgy input and then provide UI cues as to why it isn’t acceptable. I’m holding off doing this myself just in case it turns up in the standard library, perhaps when Orcas ships? If it doesn’t, I’ll post animplementation because my project needs one. Masking input to a WPF TextBox February 15, 2007
Posted by Karl Hulme in .Net, C#, WPF, XAML.
trackback private void TextChangedEventHandler(Object sender, EventArgs e)
{
TextBox textBox = sender as TextBox;
Int32 selectionStart = textBox.SelectionStart;
Int32 selectionLength = textBox.SelectionLength;
String newText = String.Empty;
foreach (Char c in textBox.Text.ToCharArray())
{
if(Char.IsDigit(c) || Char.IsControl(c)) newText += c;
}
textBox.Text = newText;
textBox.SelectionStart = selectionStart <= textBox.Text.Length ?
selectionStart : textBox.Text.Length;
}
private Boolean IsTextAllowed(String text)
{
foreach (Char c in text.ToCharArray())
{
if (Char.IsDigit(c) || Char.IsControl(c)) continue;
else return false;
}
return true;
}
private Boolean IsTextAllowed(String text)
{
return Array.TrueForAll<Char>(text.ToCharArray(),
delegate(Char c) { return Char.IsDigit(c) || Char.IsControl(c); });
}
<TextBox PreviewTextInput="PreviewTextInputHandler"
DataObject.Pasting="PastingHandler" />
// Use the PreviewTextInputHandler to respond to key presses
private void PreviewTextInputHandler(Object sender, TextCompositionEventArgs e)
{
e.Handled = !IsTextAllowed(e.Text);
}
// Use the DataObject.Pasting Handler
private void PastingHandler(object sender, DataObjectPastingEventArgs e)
{
if (e.DataObject.GetDataPresent(typeof(String)))
{
String text = (String)e.DataObject.GetData(typeof(String));
if (!IsTextAllowed(text)) e.CancelCommand();
}
else e.CancelCommand();
}