Using IValueConverter in Silverlight

So data binding really is a great thing, especially when it can go beyond the boundaries of just putting text or numbers into the required fields on a form.  I was talking with someone about my current project and they made the distinction between data and information, where information is data that had been converted into some useful form.  In essence, that's what the System.Windows.Data.IValueConverter is for in Silverlight and WPF; to take some piece of data and make it meaningful within the current context.

 

My recent example was from a program I wrote that involved the user uploading some files and then tagging them with the required metadata (Name, Caption for pictures, etc.).  I had a validator for saving the information so that I could give the user a warning if something was left incomplete, but I wanted it to be both easier to see and for it to be instantly responsive to changes in the data.  The goal was for user to see, at a glance, if all the current files were valid and, if not, which ones needed to be fixed.  So I started with the template for the Listbox containing my data files:

   1: <ListBox x:Name="PictureListBox">
   2:   <ListBox.ItemTemplate>
   3:     <DataTemplate>
   4:       <Grid>
   5:         <Grid.ColumnDefinitions>
   6:           <ColumnDefinition Width="104" />
   7:           <ColumnDefinition Width="*" />
   8:         </Grid.ColumnDefinitions>
   9:         <Rectangle Grid.Column="0" 
  10:           Fill="{Binding IsValid, Converter={StaticResource ValidationConverter}}" />
  11:         <Image Grid.Column="0" Height="100" Width="100" 
  12:           Source="{Binding Path}" />
  13:         <StackPanel Grid.Column="1" >
  14:           <... some other stuff that I'm binding... />
  15:         </StackPanel>
  16:       </Grid>
  17:     </DataTemplate>
  18:   </ListBox.ItemTemplate>
  19: </ListBox>

Each image in the listbox now has a rectangle behind it that will serve as a border.  I?m binding the fill property of that rectangle to the IsValid property on my data object.  Previously, I might have tried either binding this property to a separate object or, worse yet, including the proper color as another property in my data object.  Both of these could work for a small app like mine, but they don't feel right.  Hence the converter, which my xaml is made aware of like so:

   1: <UserControl.Resources>
   2:     <my:PictureValidationConverter x:Key="ValidationConverter" />
   3: </UserControl.Resources>

and finally the code for the converter:

   1: public class PictureValidationConverter:IValueConverter
   2:    {
   3:       public object Convert(object value, Type targetType, 
   4:          object parameter, System.Globalization.CultureInfo culture)
   5:       {
   6:          if ((bool)value)
   7:          {
   8:             return new SolidColorBrush(Colors.Green);
   9:          }
  10:          else
  11:          {
  12:             return new SolidColorBrush(Colors.Red);
  13:          }
  14:       }
  15:  
  16:       public object ConvertBack(object value, Type targetType, 
  17:          object parameter, System.Globalization.CultureInfo culture)
  18:       {
  19:          throw new NotImplementedException();
  20:       }
  21:    }
I actually modified the code to more cleanly fit here.  Using a ternary operator, it was a single line of code and all without touching the data object or having to go through some elaborate convulsions to avoid doing so.  The best part is that the update is instant; as soon as I've finished entering the data, the object can see if it's valid and the image border goes from red to green. 

Posted by: Raumornie
Posted on: 9/21/2009 at 1:38 PM
Tags: , ,
Categories: Software Kata
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading