For now, I will just limit data entry to valid numbers. That doesn’t mean Char.IsNumeric. Commas and periods are valid. I also have to remember valid keys like shift, backspace, and tab.
Option 1: KeyDown
Our code-behind could simple be:
In the code above, see where I call AddHandler()? This is important because not all keystrokes are bubbled to KeyDown. AddHandler works around this. And see e.Handled? Setting that to false cancels the keystroke. The logic in ParseDouble() is here.
Option 2: InputScope
InputScope is awfully easy to handle in XAML:
Option 3: BindingValidationError
Our XAML changes like this:
In the code above, see BindingValidationError attached to the StackPanel? Attaching to the StackPanel let’s me handle more than one TextBox. I would have attached to the TextBox. But, also notice ValidatesOnExceptions (by-passes the need to use ExceptionValidationRule explicitly) and NotifyOnValidationError. These are necessary.
With this code-behind:
In the code above, we have a workaround? WPF has UpdateSourceTrigger=PropertyChanged (OnPropertyChanged in Windows Forms) that causes the underlying object to update as the user changes any part of the property’s value. Windows Phone does not support this. But this code makes it work. To validate as uses type, we need this. Otherwise we validate on Blur.
In the code above, we’re handling the error. The framework has “caught” the error for us, and bubbled it here. Using e.Action we can detect the new error. Using e.OriginalSource we can detect the specific TextBox (or any control) that caused it. Then, show the user the message.
In the code above, this is our sample DTO. It’s simple, eh? And, as you can see, all we do is raise an exception in the setter. No special interface. No special base class. No special exception. This is truly a great option for Silverlight developers.
Option 4: ExceptionValidationRule
Your XAML would look like this:
However, these are not supported in Windows Phone. Why even mention them? These are tools for WPF developers. It’s worth knowing what your limits are.
Option 5: Data Annotations
Your Classes would look like this:
However, these are not supported in Windows Phone. Why mention them? These are very compelling validation tools. It’s worth knowing what your limits are.
Option 6: IDataErrorInfo
The UI result is identical to Option 2:
The XAML is identical to Option 2:
The code-behind is not the same (but close):
In the code above, look at the setter. Where, in Option 2 we threw an exception when the parse failed, here we add to the error list (in our case a dictionary). You might be wondering about that Error property throwing a NotImplementedException? It turns out the interface includes that as a convenience to the developer (no thanks) and is not used by the Binding engine.
Option 7: INotifyDataErrorInfo
Well isn’t that a fine howdy-do? We go through all this work to use Data Binding validation only to be told we should use INotifyDataError. Then we go through all that work only to be told we should be using INotifyDataErrorInfo. Good news! This is it – the prescribed approach.
Why is this worthwhile? Well, let’s consider how IDataErrorInfo works. Right after the data value is set, the error list is queried. This expects the validation to nearly immediate. What if your validation took some time? You need an event, you need INotifyDataErrorInfo.
The UI looks the same (exactly):
The XAML looks the same (exactly):
Even the code-behind looks almost the same:
In the code above, there are only a few changes from the IDataErrorInfo implementation. Specifically, the presence of the ErrorsChanged event. This alerts the UI to “come look again!” for validation errors. Using this approach allows for validation to take as long as it needs – like calling to a service – using an async call.
Please note: I did not implement an async operation in my sample. For more on Windows Phone async operations, look at this article. For more information in calling out to a service, look at this article.
Option 8: Custom
Here’s the XAML:
In this sample we’re using attached properties – attached to the error label. The format and the textbox are specified. The code-behind does the rest – checking the value, adding the error message, changing the background color.
Here’s our code-behind:
In the code above, see the Setup() method? This is called by both properties because the they could be set in any order. But this is where we attach to the TextChanged event. In that handler, we test the format, and update the UI based on the result. And this is quite generic. I like it.
As an aside, in a WPF project we actually added a custom behavior to the TextBox control. This is yet another option for you. Actually, the sky is pretty much the limit for your custom solution.