Binding combobox to Enum in silverlight

These days I’m playing a bit with Silverlight, to realize a little piece of backoffice of an ASP.NEt classic application. We decided to give a chance to silverligth because the backoffice is used only internally and so we can make experience with a noncritical piece of software.

Even If I do not adopt a MVC or M-V-VM pattern I like to create a little domain model, than expose it with a transaction script pattern, make it avaliable through a WCF service, and create interface with really no logic. Each service method return DTO not real domain object,  this make possible for the caller not to worry about all the crap that can exists in the domain. The silverlight interface is a simple series of control, that can be bound to a DTO, so the typical pattern is to ask service for some object, then bind them to a control, let the user play with the interface and thanks to twoway binding we can simply wait for the user to press a “Save” button or other such events to call update method from the service.

Thanks to DTO all the work to update the real domain object is done by the service, that can do whatever check you want (optimistic concurrency,etc). The question is “how far can we push silverlight binding to avoid to write any code to make the DTO synchronized with the UI?” The answer is  “really far”.

As an example you can download this code, that shows you how you can bind a property of an object of some Enum type, both to a series of radio button and to a textbox. The example is a modified version of the enum binder that you can find from this article where you can find also a lot of good example about binding. The key of everything is in the IValueConverter interface that permits you to convert from a type to another and back. Here is my enum converter.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    public class EnumConverter : IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType.IsAssignableFrom(typeof(Boolean)) && targetType.IsAssignableFrom(typeof(String)))
                throw new ArgumentException("EnumConverter can only convert to boolean or string.");
            if (targetType == typeof(String))
                return value.ToString();

            return String.Compare(value.ToString(), (String) parameter, StringComparison.InvariantCultureIgnoreCase) == 0;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType.IsAssignableFrom(typeof(Boolean)) && targetType.IsAssignableFrom(typeof(String)))
                throw new ArgumentException("EnumConverter can only convert back value from a string or a boolean.");
            if (!targetType.IsEnum)
                throw new ArgumentException("EnumConverter can only convert value to an Enum Type.");

            if (value.GetType() == typeof(String))
            {
                return Enum.Parse(targetType, (String)value, true);
            }
            else
            {
                //We have a boolean, as for binding to a checkbox. we use parameter
                if ((Boolean)value)
                    return Enum.Parse(targetType, (String)parameter, true);
            }
            return null;
        }

        #endregion
    }

This is a first try implementation, not fully tested but it seems to work quite well. It handles conversion between the original enum type to a string or to a boolean value. The conversion to boolean value is needed to use it withRadioButton, in combination with the ConversionParameter. Back conversion is also implemented so you can easily use the twoway binding. Here is a typical use in a user control.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<UserControl x:Class="TestSilverlight.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:TestSilverlight="clr-namespace:TestSilverlight" 
    Width="400" Height="300"
     Loaded="ControlLoaded">
    <UserControl.Resources>
        <ResourceDictionary>
            <TestSilverlight:EnumConverter x:Key="EnumConverter"/>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="1"    >
            <RadioButton GroupName="TestEnum" Content="One" 
                             IsChecked="{Binding Path=TestProp, ConverterParameter=one, Mode=TwoWay, Converter={StaticResource EnumConverter}}" />
            <RadioButton GroupName="TestEnum" Content="Two" 
                             IsChecked="{Binding Path=TestProp, ConverterParameter=two, Mode=TwoWay, Converter={StaticResource EnumConverter}}" />
            <RadioButton GroupName="TestEnum" Content="Three" 
                             IsChecked="{Binding Path=TestProp, ConverterParameter=three, Mode=TwoWay, Converter={StaticResource EnumConverter}}" />
            <RadioButton GroupName="TestEnum" Content="Four" 
                             IsChecked="{Binding Path=TestProp, ConverterParameter=four, Mode=TwoWay, Converter={StaticResource EnumConverter}}" />
            <TextBox Text="{Binding Path=TestProp, Mode=TwoWay, Converter={StaticResource EnumConverter}}" />
        </StackPanel>
    </Grid>
</UserControl>

As you can see for the textbox you need no particular stuff to do, only set the converter, but for the RadioButton you should set the ConverterParameter for each RadioButton to set the corresponding enum value. The game is done, my DTO object stay in sync with interface with no line of code :D

alk.

Tags: Silverlight