Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Flexible and Powerful Data Binding with WPF, Part 2 : Page 3

Microsoft has been building data binding frameworks for years. Each one promises to solve our data binding woes forever. We're still waiting for the perfect one—but we're getting closer!


advertisement

Validation

The potential for getting corrupt input data is higher when implementing a TwoWay binding. Good UI design attempts to reduce input errors by narrowing input choices and guiding the user through a well-defined set of controls. The accumulation of experience in UI design has shown that limiting the user to a small set of items in a ListBox is a better option than allowing the user to input ad hoc text. Fortunately, the WPF binding engine implements a validation system that simplifies the validation process.

A reasonable separation of concerns for validation looks like this:

  • The business class provides the validation rules and enforces them.
  • The UI provides feedback to the user supplying visual cues indicating which controls are invalid. If the business class offers explanatory information regarding the error, the UI should also show these details to the end user. For a thorough discussion of object binding in Windows Forms, see Deborah Kurata's Mar/Apr 2006 CoDe Magazine article "Object Binding Tips and Tricks."

Business Class Validation

Deciding when you should validate an object is a subject open to frequent debate. Experts all agree that a business object must validate any inbound data and notify the client code when the data is unacceptable. Where they disagree is in how and when to do this. There is one school that states: "Always throw an exception when incoming data is invalid." While this rule is simple to understand it doesn't always fit well in data-binding or multi-tier application scenarios. There are lots of alternate architecture choices, but for this article I'll look at only two: the "Throw Exception" implementation, and the IDataErrorInfo implementation.

The Throw Exception model is so simple it doesn't require much explanation. If the incoming property value is invalid, throw an exception. That's really all there is to this model.

The IDataErrorInfo model requires only slightly more work. The IDataErrorInfo interface has been part of .NET for years. Originally intended to return a list of errors to a Windows Forms UI. WPF 3.5 added support for this interface so you can use it to report error details to your WPF UI too. The IDataErrorInfo interface is simple to implement. Create a read-only Error property that returns an error string and an Indexer that returns a specific error by name.

// C#: string IDataErrorInfo.Error { get{ return _errorString; } } string IDataErrorInfo.this[string propertyName] { get{ return (string)_errorDetails[propertyName]; } }

In Visual Basic:

Public ReadOnly Property [Error]() As String _ Implements IDataErrorInfo.Error Get Return _errorString End Get End Property Default Public ReadOnly Property Item _ (ByVal propertyName As String) As String _ Implements IDataErrorInfo.Item Get Return _errorDetails(propertyName) End Get End Property

You can see the full implementation of the IDataErrorInfo interface in Listing 2.

Validation Feedback in the UI

It's not enough for the business class to reject the data. You have to inform your users of the problem and show the errors in the user interface too. Once again Microsoft provides the answer with two properties on the Binding class: ValidatesOnExceptions and ValidatesOnDataErrors.

When you set ValidatesOnExceptions to true, WPF monitors any attempt to update the source property, and when an exception is thrown, WPF draws a red border over the outline of the offending bound element. WPF draws the error border in a special area, called the Adorner layer, which is the last layer drawn (highest Z-Order) by the WPF renderer. Therefore the red border (or your custom error template if you have one), is always superimposed on the normal UI:

 
Figure 1. Red Exception Border Example: The default validation in WPF shows a simple red border.


<TextBox Margin='20' Text="{Binding Source= {StaticResource emp}, Path=FirstName, Mode=TwoWay, ValidatesOnExceptions =true}" />

In Figure 1 you can see what the Red Exception Border looks like in the UI.

The Red Border is simple—but very plain. Admit it. You were thinking that the Red Border was lame. You've seen the ASP.NET or Windows Forms error providers and you know that there are better looking error icons available. Even though WPF provides only this simple error template, you're not stuck with it. The WPF UI is based on a templating model, so you can transform any UI control instantly to a radical new appearance using a template. That's the solution to the red border crisis; create a replacement UI with an error template.

Build an Error Template

You typically define control templates as part of a style. For Error Templates, the template is part of the Validation.ErrorTemplate setter. The following XAML shows the first few lines of the style. The style applies only to text boxes; within the Validation.ErrorTemplate setter there is a ControlTemplate section:

<Style TargetType="{x:Type TextBox}"> <Setter Property='Margin' Value='0,0,40,0' /> <Setter Property="Validation.ErrorTemplate"> <Setter.Value> <ControlTemplate> <DockPanel LastChildFill="True">

Control templates can contain any valid WPF elements, so you should have fun creating the control template. In the next example, I've added a DockPanel and a TextBlock. The TextBlock uses a WingDing that looks like a small circular ring. Don't forget to tell WPF where to place the Error Template in the Adorner layer by adding the element. The placeholder represents the real UI control that has the binding exception. The original control will still be visible, and WPF will draw the replacement error template in the same location as the original control:

<DockPanel LastChildFill="True"> <TextBlock DockPanel.Dock="Right" Foreground="Orange" FontFamily='WingDings' FontSize="14" FontWeight="Bold" ToolTip='{Binding ElementName=customAdorner, Path=AdornedElement. (Validation.Errors)[0].ErrorContent}'>&#163; </TextBlock> <AdornedElementPlaceholder Name="customAdorner" /> </DockPanel>

 
Figure 2. Custom Error Template Example: By replacing the default validation template with a custom validation template, you can change the error display to whatever you like.
The key takeaway is to retrieve the original exception information and use the following XAML in your template:

Path=AdornedElement. (Validation.Errors)[0].ErrorContent}'

Figure 2 shows how the custom error template looks in the UI.

ValidatesOnDataErrors

The ErrorProvider component in Windows Forms relies on an eventing model to receive error notifications from the business class. WPF supports the same model, you just have to implement the IDataErrorInfo interface in the business class, and use the ValidatesOnDataErrors property in your XAML binding:

<TextBox Text="{Binding Source= {StaticResource emp}, Path=FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" />

Setting ValidatesOnDataErrors to True enables the built-in validation rule that checks for errors raised by the IDataErrorInfo data source. When an error is raised, the binding engine creates a ValidationError object and adds it to the Validation.Errors collection of the bound element. The resulting UI looks the same as the previous exception-based example, but WPF sends the error information using an event instead of by raising an exception.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date