It is dangerous to bind Radio Buttons to an enumeration with ValueConverter!

Binding a set of Radio Buttons to an enumeration is ubiquitous task but it’s not as easy as it might seem at first glance.

The Problem

One proposed way to do this is to bind each RadioButton IsChecked property to the property (defined somewhere in data model) providing current (selected) enumeration value and use ValueConverter with parameter to convert this current value to boolean and vice versa. This approach is recommended in some rather recent blog and forum posts, e.g. WPF: How to bind RadioButtons to an enum?, Databinding enum to radiobuttons, etc. It works when you change current enumeration value by hands in UI, but if you do it in code the button loses its binding! In that case you have the bug which isn’t easy to reveal.

The Example

Mark Smith (Julmar) uncovered the reason of this behavior in his excellent blog post MVVM: Binding RadioButton groups. In this post I want to show what happens by example. I took most of the code relevant to Radio Buttons to the enumeration binding from WPF: How to bind RadioButtons to an enum? forum thread. The window of the example looks like follows:

 

Fig. 1 Example screen until you change selections by clicking RadionButtons.

There are two panes in this window with subtle differences.

The left pane uses ValueConverter named “EnumBooleanConverter”:

public class EnumBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null)
            return DependencyProperty.UnsetValue;

        if (Enum.IsDefined(value.GetType(), value) == false)
            return DependencyProperty.UnsetValue;

        object parameterValue = Enum.Parse(value.GetType(), parameterString);

        return parameterValue.Equals(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string parameterString = parameter as string;
        if (parameterString == null || value.Equals(false))
            return DependencyProperty.UnsetValue;

        return Enum.Parse(targetType, parameterString);
    }
}
and corresponding XAML:
<StackPanel>
    <RadioButton Name="rb11" IsChecked="{Binding Path=CurrentChoice1, 
        Converter={StaticResource enumBooleanConverter}, 
        ConverterParameter=One}">One</RadioButton>
    <RadioButton Name="rb12" IsChecked="{Binding Path=CurrentChoice1, 
        Converter={StaticResource enumBooleanConverter}, 
        ConverterParameter=Two}">Two</RadioButton>

    <Button Click="btnNext1_Click" Margin="2">Next choice</Button>
    <Button Click="btnRandom1_Click" Margin="2">Random choice</Button>
</StackPanel>

The right pane uses ValueConverter named “EnumBooleanConverter2”:

public class EnumBooleanConverter2 : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.Equals(parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value.Equals(false))
            return DependencyProperty.UnsetValue;
        else
            return parameter;
    }
}
and corresponding XAML:
<StackPanel>
    <RadioButton Name="rb21" IsChecked="{Binding Path=CurrentChoice2, 
        Converter={StaticResource enumBooleanConverter2}, 
        ConverterParameter={x:Static local:Choices.One}}"
        Content="{x:Static local:Choices.One}"/>
    <RadioButton Name="rb22" IsChecked="{Binding Path=CurrentChoice2, 
        Converter={StaticResource enumBooleanConverter2}, 
        ConverterParameter={x:Static local:Choices.Two}}"
        Content="{x:Static local:Choices.Two}"/>
    ...
    <Button Click="btnNext2_Click" Margin="2">Next choice</Button>
    <Button Click="btnRandom2_Click" Margin="2">Random choice</Button>
</StackPanel>

 

Both panes behave the same way. Until you change selected value by clicking RadionButtons all works fine and the screen looks like in Fig. 1. the “Current choice” filed reflects the option selected and the “Binding expr” field shows text “not null”: this means that RadionButton IsChecked property keeps the binding set in XAML. But if you click “Next” and, especially, “Random” buttons some times the picture changes radically:

Fig. 2 Example screen after you clicked “Next” or “Random” buttons some times.

As you can see the “Binding expr” field shows text “null”: this means that RadionButton IsChecked property lost the binding set in XAML and the current value property is no more connected to the RadioButton. You still can click a RadioButton and it will shows up in checked state but the current value property wouldn’t change.

Conclusion

You can bind Radio Buttons to an enumeration using ValueConverter on your own risk and only if you are sure that you won’t ever change the current value property programmatically.

Code

You can download VS 2008 example solution here

Advertisements

About ovpwp

I am engaged in programming, maintenance and supply of computing technique since 1970. Started with the computers M, BESM, Minsk series and received appropriate education in the least, in which it was then possible in THE USSR. Then he went the usual way - ES series, IBM 360/370, Sun Spark, Ibm Power & PS2, PC. Programming started in the code (machine commands), then were sorts of assemblers, Algol, FORTRAN, PL/1, C, C , VB, C#. It is only the ones that I used the production scale; but there were, of course, others like List, Modula, Pascal, Java, etc. Currently I prefer .NET platform for desktop development. I don't really like web-programming (probably because of the inability for quality design), but I have enough experience in site building in LAMP environment using PHP.
This entry was posted in Uncategorized. Bookmark the permalink.

One Response to It is dangerous to bind Radio Buttons to an enumeration with ValueConverter!

  1. Scott says:

    Hi Oleg,

    I just happened to run across your post about an answer I provided on StackOverflow. (I submitted the second converter option). A while back (yet after your post) I updated my answer which happens to fix the issue you discuss in this post. In the ConvertBack method, instead of returning DependencyProperty.UnsetValue, I return Binding.DoNothing.

    I believe this fixes the issue, though I couldn’t verify against your code as I could not find the link. I am interested in seeing if it fixed the problem for you however.

    My answer is the EnumToBooleanConvert (not the selected answer).
    http://stackoverflow.com/questions/397556/wpf-how-to-bind-radiobuttons-to-an-enum

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s