Databinding to an enumeration in WinRT

This article demonstrates how to databind a radiobutton to an enumeration element, in a WinRT Metro application. The MVVM viewmodel has a property of an enumeration type, which is bound to the IsChecked property of some radiobuttons. A value converter compares the value from the viewmodel with an enumeration element that is provided as parameter to the converter. The Convert method returns true if both match, the ConvertBack method updates the bound value when the radiobutton is clicked or tapped.
 
Here's a screenshot of the attached sample application. The radiobuttons are bound to the CarColor property -an enumeration- of the viewmodel. The Vote-button updates that same property through a command:

The converter is much more complex than the WPF version from my previous article, it's even more complex than its corresponding Silverlight version that you can find here.

Here's a list of reasons why the implementation was not so straightforward:

  • The x:Static markup extension is not allowed in a Metro application,
  • Binding.DoNothing does not exist in WinRT, and
  • unlike in WPF or Silverlight, the converter receives the enumeration value as an integer instead of a string.

When I observed all of this, my first reaction was AARGH!!! Don't worry: it was not a call of anger and frustration. In the noble Antwerp language aerg just means 'this is bad'. Non-believers: just follow this link.

As a result, the converter is much more complex than expected. It reconstructs the enumeration parameter from the binding expression by string parsing and reflection. Here's how it looks like:

namespace U2UConsult.WinRT.Converters
{
    using System;
    using System.Globalization;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Data;

    /// <summary>
    /// Converts an enum to a boolean.
    /// </summary>
    public class EnumToBooleanConverter : IValueConverter
    {
        /// <summary>
        /// Compares the bound value with an enum param. Returns true when they match.
        /// </summary>
        public object Convert(object value, string typeName, object parameter, string language)
        {
            try
            {
                string parm = parameter.ToString();
                int lastDot = parm.LastIndexOf(".");
                string enumName = parm.Substring(0, lastDot);
                string enumValue = parm.Substring(lastDot + 1);

                Type t = Type.GetType(enumName);
                string s = Enum.GetName(t, value);
                object b = Enum.Parse(t, enumValue);
                return b.ToString() == s;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Converts the boolean back into an enum.
        /// </summary>
        public object ConvertBack(object value, string typeName, object parameter, string language)
        {
            try
            {
                string parm = parameter.ToString();
                int lastDot = parm.LastIndexOf(".");
                string enumName = parm.Substring(0, lastDot);
                string enumValue = parm.Substring(lastDot + 1);

                Type t = Type.GetType(enumName);
                object b = Enum.Parse(t, enumValue);

                return b;
            }
            catch (Exception)
            {
                return DependencyProperty.UnsetValue;
            }
        }
    }
}

In your application, all you need to do is create an enumeration:

public enum CarColor
{
    Yellow,
    Red,
    Pink,
    Black
}

In the viewmodel, create a property of the enumeration type:

private CarColor carColor = CarColor.Black;

public event PropertyChangedEventHandler PropertyChanged;

public CarColor CarColor
{
    get { return carColor; }
    set {
        this.carColor = value;
        this.PropertyChanged.Raise(this, (o) => o.CarColor);
    }
}

The propertychanged notification makes sure that the radiobutton follows all modifications of the property.
 
In the view, define the converter instance as a resource in XAML:

<UserControl.Resources>
    <cv:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
</UserControl.Resources>

Bind the viewmodel's CarColor property to the Ischecked property of each radioButton. The enumeration value is provided as parameter to the converter with its fully qualified name. Also, you have to set the binding mode to TwoWay, and make sure that every radiobutton has its own GroupName. This is because we can't use Binding.DoNothing in the IValueConverter.ConvertBack Method. We always have to return the parameter, or DependencyProperty.UnsetValue. Both (re-)trigger all radiobuttons in the same group and that's not what we want; more info here.

Here's the full binding syntax in XAML:

<RadioButton Content="Giallo Modena"
                GroupName="Yellow"
                IsChecked="{Binding CarColor, Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=U2UConsult.WinRT.DataBindingToEnum.ViewModels.CarColor.Yellow}" />
<RadioButton Content="Rosso Corsa"
                GroupName="Red"
                IsChecked="{Binding CarColor, Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=U2UConsult.WinRT.DataBindingToEnum.ViewModels.CarColor.Red}" />
<RadioButton Content="Rosa Insapora"
                GroupName="Pink"
                IsChecked="{Binding CarColor, Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=U2UConsult.WinRT.DataBindingToEnum.ViewModels.CarColor.Pink}" />
<RadioButton Content="Matte Nero"
                GroupName="Black"
                IsChecked="{Binding CarColor, Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=U2UConsult.WinRT.DataBindingToEnum.ViewModels.CarColor.Black}" />

This solution is more error-prone and definitely slower than the WPF version, but it does the job. That's the good news. I also have bad news: the pink Ferrari photo is NOT photoshopped, aerg.

Anyway, here's the full source code. It was developed with Visual Studio 11 Developer Preview: U2UConsult.WinRT.DataBindingToEnum.zip (364,11 kb)

Enjoy!