One of the most powerful aspects of XAML is it’s rich and dynamic support for data binding.
MSDN: Data binding provides a simple way for Silverlight-based applications to display and interact with data. The way data is displayed is separated from the management of the data. A connection, or binding, between the UI and a data object allows data to flow between the two. When a binding is established and the data changes, the UI elements that are bound to the data can reflect changes automatically. Similarly, changes made by the user in a UI element can be reflected in the data object. For example, if the user edits the value in a TextBox, the underlying data value is automatically updated to reflect that change.
In XAML, data binding to an object’s property returns that property’s value. If the value is “Jerry” then you get “Jerry”.
In this article we will discuss how we can convert the value of a property to something else – something we need in our UI.
Data Binding
Let’s take a minute to look at simple data binding in XAML.
Consider this DTO model:
To data bind to it, we do this:
Then we give it data, like this:
Then, the UI looks like this:
This is great. Data binding is working, and there is no code behind necessary to put values into our UI controls.
Sidebar: since the DTO model does not implement the INotifyPropertyChanged interface (which introduces the PropertyChanged event) the UI will not reflect changes to the property values if they are changed behind the scenes. I talk more about this here.
The Problem
The output is handy, but not perfect. What use is “true” in the output?
We need to convert the value of “true” to “Boy” or “Girl” respectively.
Solution 1: Class Changes
Class Changes allow us to encapsulate complex formatting logic into the class like this:
This let’s you do this:
This is handy because formatting travels with the class wherever it goes.
This is horrible because UI logic is inside your DTO model – it might be right for this UI, but it might be wrong for the next UI.
We don’t want MailFormattedVersion1 and then MailFormattedVersion2 and then more!
We need another option.
Solution 2: String Formatting
String formatting is a great part of the XAML data binding engine. It lets you format the property’s value by using standard .Net format strings. Best of all it lets you do it right in the XAML.
Note: Support for StringFormat was introduced with Mango.
Note: the following samples use the following class:
Appending Text
A simple binding would look like this:
Looks like:
We could append to the values with the following syntax:
In the code above, see the StringFormat added to the Binding syntax? This property gives you the ability to specify surrounding text to append to the current value.
Looks like:
Formatting Text
In a addition to the ability to append text to the value, you can also use the standard .Net format strings to format the value.
In the code above, see where we changed the {0} to {0:d}? This is a standard string that formats a date to MM\DD\YYYY (or short date).
In the code above, see where we changed the {0} to {0:c0}? This is a standard string that formats a number to $#,### (or currency).
Looks like:
Unfortunately
I had to mention this option. Unfortunately, Silverlight does not apply StringFormat syntax to Booleans.
We need another option.
Solution 3: Custom Converters
A converter is a class that implements IValueConverter. (There is also the IMultiValueConverter for WPF XAML – which supports MultiBinding).
When a value is about to be inserted into the Text property of the TextBlock, it is first passed to the converter. It is the output of the converter that is then placed in the Text property of the TextBlock.
Note: A TextBlock only supports OneWay binding. As a result we need only implement Convert(). If we used a control that supported TwoWay binding, like TextBox, we would need to implement the Convert() and the ConvertBack().
Here’s the converter:
In the code above, see the Convert() method? There is our logic to convert true to Boy and false to Girl. Extracting the logic from the class and putting it in a converter does two things:
- It keeps our data properly data bound. If we were to intercept the data in some other way, it would then introduce the need to handle the subsequent binding. A converter intercepts a binding without interfering with the binding engine.
- It keeps the logic in the UI where it belongs. A converter can be reused as many times as you want. It is a simple class in your UI project. However, it is specific to the UI. This solves the problem we had above where the UI logic was stick in the model.
Here’s the XAML:
In the code above, see MyConverter? This is a static reference to my converter class that I defined above. I pass this to the Converter property of the Binding syntax (as a StaticResource). When this property is rendered, it first passes through the converter’s Convert() method.
Looks like:
Problem solved! Converters are really great.
But did you notice one problem? My “BooleanConverter” converts a Boolean value to Boy or Girl. What I had a Boolean property whose property meant IsAdministrator? I don’t think Boy or Girl are the correct for the UI.
The solution simply is to create more than one converter – as many as you need for your UI scenario. And, I know what you are thinking. Aren’t we OOP developers? Wouldn’t a reusable converter be nice? It would be nice but not necessary.
However, if you insist on a reusable converter – let me show you how.
Reusable Converters
Here’s a nice bonus. How to create a converter that can be used in more than one scenario.
I happen to already have one written:
Get the code here.
In the code above, hopefully you see this is a OneWay converter. See those properties?
Here’s what they mean:
Match | Gets or Sets the value which will be compared to the binding value. |
Then | Gets or Sets the value which will be returned if the compare is true. |
Else | Gets or Sets the value which will be returned if the compare is false. |
UseValueAsElse | Gets or Sets if the binding value will be returned if the compare is false. When true, this overrides the Else property. |
Here’s the XAML setup:
In the code above we create four converters. Actually we are just configuring four converters. It’s the same reused converter every time.
Caveat: Setting a date value from a string in XAML does not work in Silverlight. My example tests for null. It would be very difficult to test for an exact date because of this Silverlight XAML limitation.
It’s worth pointing out the TextBlock binding to Date: you can use StringFormat in conjunction with a Converter.
With this data:
We get this:
With this data:
We get this:
A complex example
In this example, the button is visible only when IsAdminisrtator property is true. The reusable converter effectively switches between Visible and Collapsed based on the true/false value of the Boolean.
In the code above, see how I make a reference to System.Windows so that I can set the value of Visibility enumeration? You can do this with any enumeration – even more complex types like Thickness.
A reusable converter is stinking handy. It can’t be reused for every single circumstance, I realize that. But it can be reused for many of them (maybe even 90% of them).
The best part of a reusable converter is that the definition of the converter is in the XAML, where it is used. That’s handy for developers.
Conclusion
Data binding is a core feature of Silverlight and you should not ignore it. It saves code behind and accomplishes UI updates when backend data changes occur.
However, you need to learn how to use it.
As for formatting data from your objects, you have different solutions to choose.
- Change your class – this is very effective but has the unfortunate consequence of putting your UI logic in your DTO. That may not matter to you.
- Use FormatString – this is very effective for most data types but does not work for all, like Boolean. Also your formatting requirements may be too complex for FormatString.
- Use a Converter – this is very effective to componentize your UI code and for every single data type – even complex types. However, too many converters in your project may become confusing so you might consider a reusable converter.
You have lots of options and good reasoning for each. You are your developer, not me. I cannot make the choice for you – I can just give you the choices and the thinking behind them. Choose wisely.
Best of luck!
0 comments:
Post a Comment