One of the reasons why the ViewModel pattern is so powerful in Silverlight and WPF is because Binding Converters can do so much.  As we saw in HelloWorld.ViewModel, a ViewModel can expose a boolean property that is consumed as a Visibility value for controls.  This requires some glue to convert the boolean to the necessary enum, and that’s where our VisibilityConverter comes in.  If you want to see this in action, go check out the sample code, but here’s how the VisibilityConverter works.

In order to create any binding converter, you can start off by creating a class that implements System.Windows.Data.IValueConverter.  This is the interface that defines how we will convert data and optionally convert it back.  Not surprisingly, IValueConverter defines two methods, Convert and ConvertBack.  Here’s the metadata from the class, which explains how they’re used pretty well.

   1: using System;
   2: using System.Globalization;
   3:  
   4: namespace System.Windows.Data
   5: {
   6:     // Summary:
   7:     //     Exposes methods that allow modifying the data as it passes through the binding
   8:     //     engine.
   9:     public interface IValueConverter
  10:     {
  11:         // Summary:
  12:         //     Modifies the source data before passing it to the target for display in the
  13:         //     UI.
  14:         //
  15:         // Parameters:
  16:         //   value:
  17:         //     The source data being passed to the target.
  18:         //
  19:         //   targetType:
  20:         //     The System.Type of data expected by the target dependency property.
  21:         //
  22:         //   parameter:
  23:         //     An optional parameter to be used in the converter logic.
  24:         //
  25:         //   culture:
  26:         //     The culture of the conversion.
  27:         //
  28:         // Returns:
  29:         //     The value to be passed to the target dependency property.
  30:         object Convert(object value, Type targetType, object parameter, CultureInfo culture);
  31:         //
  32:         // Summary:
  33:         //     Modifies the target data before passing it to the source object. This method
  34:         //     is called only in System.Windows.Data.BindingMode.TwoWay bindings.
  35:         //
  36:         // Parameters:
  37:         //   value:
  38:         //     The target data being passed to the source.
  39:         //
  40:         //   targetType:
  41:         //     The System.Type of data expected by the source object.
  42:         //
  43:         //   parameter:
  44:         //     An optional parameter to be used in the converter logic.
  45:         //
  46:         //   culture:
  47:         //     The culture of the conversion.
  48:         //
  49:         // Returns:
  50:         //     The value to be passed to the source object.
  51:         object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
  52:     }
  53: }


When using one-way binding from your ViewModel to your View, like we did with our Visibility on our images, you only need to implement the Convert method.  But if you need to support two-way binding where the View can call the setter on your ViewModel, then you need to also implement the ConvertBack method.  The VisibilityConverter that I created supports two-way binding.

The first time I wrote VisibilityConverter, I simply checked the boolean value specified, and if it was true, I returned Visibility.Visible; if false, I returned Visibility.Collapsed.  But it wasn’t long before I realized that wouldn’t do.  As we saw in HelloWorld, I need to be able to reverse the behavior.  That’s where our ConverterParameter is used.

Your ConverterParameter is passed in as an object but for the most part, you’ll get the value as a string.  If you programmatically set up a binding, I suppose you could get the value as something else, but through declarative binding, you’ll get the value as string.  This allows you to pass extra data to your binding converter though, so that the converter can make decisions based on this parameter.  As used in the VisibilityConverter, I am specifying what Visibility value to use when the bound value is true.

Let’s take a look at the code for Convert.

   1: /// <summary>
   2: /// Convert a boolean value to a Visibility value
   3: /// </summary>
   4: /// <param name="value"></param>
   5: /// <param name="targetType"></param>
   6: /// <param name="parameter">ConverterParameter is of type Visibility</param>
   7: /// <param name="culture"></param>
   8: /// <returns></returns>
   9: public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  10: {
  11:     bool isVisible = (bool)value;
  12:  
  13:     // If visibility is inverted by the converter parameter, then invert our value
  14:     if (IsVisibilityInverted(parameter))
  15:         isVisible = !isVisible;
  16:  
  17:     return (isVisible ? Visibility.Visible : Visibility.Collapsed);
  18: }


I’m making use of a private method called IsVisibilityInverted, which is defined here:

   1: /// <summary>
   2: /// Determine the visibility mode based on a converter parameter.  This parameter is of type Visibility,
   3: /// and specifies what visibility value to return when the boolean value is true.
   4: /// </summary>
   5: /// <param name="parameter"></param>
   6: /// <returns></returns>
   7: private static Visibility GetVisibilityMode(object parameter)
   8: {
   9:     // Default to Visible
  10:     Visibility mode = Visibility.Visible;
  11:  
  12:     // If a parameter is specified, then we'll try to understand it as a Visibility value
  13:     if (parameter != null)
  14:     {
  15:         // If it's already a Visibility value, then just use it
  16:         if (parameter is Visibility)
  17:         {
  18:             mode = (Visibility)parameter;
  19:         }
  20:         else
  21:         {
  22:             // Let's try to parse the parameter as a Visibility value, throwing an exception when the parsing fails
  23:             try
  24:             {
  25:                 mode = (Visibility)Enum.Parse(typeof(Visibility), parameter.ToString(), true);
  26:             }
  27:             catch (FormatException e)
  28:             {
  29:                 throw new FormatException("Invalid Visibility specified as the ConverterParameter.  Use Visible or Collapsed.", e);
  30:             }
  31:         }
  32:     }
  33:  
  34:     // Return the detected mode
  35:     return mode;
  36: }
  37:  
  38: /// <summary>
  39: /// Determine whether or not visibility is inverted based on a converter parameter.
  40: /// When the parameter is specified as Collapsed, that means that when the boolean value
  41: /// is true, we should return Collapsed, which is inverted.
  42: /// </summary>
  43: /// <param name="parameter"></param>
  44: /// <returns></returns>
  45: private static bool IsVisibilityInverted(object parameter)
  46: {
  47:     return (GetVisibilityMode(parameter) == Visibility.Collapsed);
  48: }


As you see, I actually have 2 methods; one for GetVisibilityMode and one for IsVisibilityInverted.  GetVisibilityMode is where I parse the ConverterParameter and return the Visibility value to use for true values.  IsVisibilityInverted checks to see if this is set to Collapsed.

I mentioned that I also implemented the ConvertBack method to support two-way binding.  I’m not using this yet anywhere, but as an exercise for implementing a converter, we can the see the code here:

   1: /// <summary>
   2: /// Support 2-way databinding of the VisibilityConverter, converting Visibility to a boolean
   3: /// </summary>
   4: /// <param name="value"></param>
   5: /// <param name="targetType"></param>
   6: /// <param name="parameter"></param>
   7: /// <param name="culture"></param>
   8: /// <returns></returns>
   9: public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  10: {
  11:     bool isVisible = ((Visibility)value == Visibility.Visible);
  12:  
  13:     // If visibility is inverted by the converter parameter, then invert our value
  14:     if (IsVisibilityInverted(parameter))
  15:         isVisible = !isVisible;
  16:  
  17:     return isVisible;
  18: }


We deal with our ConverterParameter in the same fashion here, and we basically reverse the code from the Convert method.

Again, you can see this converter in action in HelloWorld.ViewModel.  And if you’re using the ViewModel pattern, you might find yourself using binding converters pretty liberally, and that’s a good thing.  Keep your view-specific implementations out of your ViewModel by converting values during binding.  This allows your view to still have empty code-behind files, provides testability of the standalone converters, and it keeps your ViewModel separated from your View logic—all good things.

One last note too… don’t get stuck thinking that converters can only convert from one scalar value to another.  You can do all sorts of cool things with converters.  Just like with the ViewModel pattern in general, once you start to use converters, you’ll be hooked, and you’ll come up with all kinds of out-of-the-box ways of using them.