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