Friday, November 18, 2011

Beyond Simple Text

Binding works with all types of objects – not just simple primitive types like integers and strings. In the XAML below we are going to databind a property named Brush to the Fill property of a Rectangle.

<ListBox ItemsSource="{Binding}">     <ListBox.ItemTemplate>         <DataTemplate>             <StackPanel Orientation="Horizontal">                 <TextBlock Text="{Binding Code}" Width="90" />                 <Rectangle Fill="{Binding Brush}"                            Width="100" Height="12"                            VerticalAlignment="Center" />             StackPanel>         DataTemplate>     ListBox.ItemTemplate> ListBox> 

This XAML can bind to a collection of BrushDisplay objects we create in code. Each BrushDisplay has a Code property (of type string) that represents the hexadecimal RGB values for a color, and a SolidColorBrush property named Brush to paint the actual color. The screen shot on the right is an excerpt of what the code below will create.

byte[] v = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF };pretty colors in silverlight   var list = new List<BrushDisplay>(); for (int r = 0; r < v.Length; r++)   for(int g = 0; g < v.Length; g++)     for(int b =0; b < v.Length; b++)       list.Add(         new BrushDisplay()         {           Code = "0x" + (v[r] + (v[g] << 8) + (v[b] << 16))                          .ToString("X"),           Brush = new SolidColorBrush(               Color.FromArgb(255, v[r], v[g], v[b]))         });              this.DataContext = list; 

Of course not every data source may map perfectly to its destination. We might need to massage some data as it travels into the view, and vice versa (more on two-way data binding in a bit). In these scenarios we need a value converter. A value converter implements the IValueConverter interface. Values converters are powerful because they allow you to inject some logic into the binding process to perform conversions and formatting (a popular use of value converters is to format numbers and dates).

If you are displaying a DateTime, for example, the default conversion during databinding will create the display seen on the right. ugly DateTimeIf we only want to display the date (and no time), we can use a value converter. Value converters are easy to create – you only need to implement Convert and ConvertBack methods. The class below is designed to convert dates to strings and back again.

public class DateFormatter : IValueConverter {     public object Convert(object value, Type targetType,                            object parameter, CultureInfo culture)     {         if (parameter != null)         {             string formatString = parameter.ToString();              if (!string.IsNullOrEmpty(formatString))             {                 return string.Format(culture, formatString, value);             }         }          return value.ToString();     }      public object ConvertBack(object value, Type targetType,                                object parameter, CultureInfo culture)     {         if (value != null)         {             return DateTime.Parse(value.ToString());         }         return value;     } } 

To use this new formatter we need to include it in our XAML. You can add formatters as resources inside of user controls, pages, and even at the application level. In the XAML below we are adding an instance of the formatter inside a user control’s resource dictionary with a key of “dateFormatter”. Notice we also include an XML namespace to CLR namespace mapping (xmlns:local="clr-namespace:DataBindingDemo") so that the XAML parser knows where to find the formatter.

<UserControl Width="400"      x:Class="DataBindingDemo.EditTimeCard"     xmlns=""      xmlns:x=""      xmlns:local="clr-namespace:DataBindingDemo" >     <UserControl.Resources>         <local:DateFormatter x:Key="dateFormatter" />     UserControl.Resources>

We can then use the formatter in a data binding expression. The following XAML points to the dateFormatter key, so the formatter will be found in the application’s resources. Notice we can also pass along a ConverterParamter. In this case a “{0:d}” will tell the String.Format call to format the DateTime into a short date format (such as 1/1/2008 for a United States English culture setting).

<TextBox Margin="10" Text="{Binding                               Converter={StaticResource dateFormatter},                             ConverterParameter='{0:d}',                             Path=PayPeriod.Start}"/> 

No comments:

Post a Comment