Wednesday, February 18, 2009

WPF Radio button binding (Enums and bug fixes)

I recently began implemented binding two radio buttons to a single enumeration value on an object, and was faced with two problems:
1) How do I bind the IsChecked boolean to an enumeration?
2) Once 1) was completed and even though it was using TwoWay binding, when the enum value was set outside of the UI, then the radio button would loose it's binding.

Here are the solutions:

1) Use a ValueConverter combined with ConverterParameter to bind the enumeration to the boolean IsChecked:
XAML:
<EnumBooleanConverter x:Key="ebc" /> <!-- declared in the UserControl Resources -->
...
<RadioButton  x:Name="rdoMale" Content="Male" IsChecked="{Binding Path=Gender, Mode=TwoWay, Converter={StaticResource ebc}, ConverterParameter=Male}"/>
<RadioButton  x:Name="rdoFemale" Content="Female" Margin="5" IsChecked="{Binding Path=Gender,Mode=TwoWay, Converter={StaticResource ebc},ConverterParameter=Female}"/>

C#:

  public class EnumBooleanConverter : IValueConverter

    {

        #region IValueConverter Members

 

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

        {

            var ParameterString = parameter as string;

            if (ParameterString == null)

                return DependencyProperty.UnsetValue;

 

            if (Enum.IsDefined(value.GetType(), value) == false)

                return DependencyProperty.UnsetValue;

 

            object paramvalue = Enum.Parse(value.GetType(), ParameterString);

            return paramvalue.Equals(value);

        }

 

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

        {

            var ParameterString = parameter as string;

            if (ParameterString == null)

                return DependencyProperty.UnsetValue;

 

            return Enum.Parse(targetType, ParameterString);

        }

 

        #endregion

    }

..that worked great, until I set the value of the enum from code (ie: not by clicking the radio buton), so...

2) turns out, having read this post, it seems that if radio buttons belong to the same group, they confuse each other (or at least that's how I interpreted it). So I changed the XAML to:
<RadioButton  GroupName="Male" x:Name="rdoMale" Content="Male" IsChecked="{Binding Path=Gender, Mode=TwoWay, Converter={StaticResource ebc}, ConverterParameter=Male}"/>
<RadioButton  GroupName="Female" x:Name="rdoFemale" Content="Female" IsChecked="{Binding Path=Gender,Mode=TwoWay, Converter={StaticResource ebc},ConverterParameter=Female}"/>

... and it's "all sorted m8!" :)

10 comments:

akjoshi said...

Thanks jax, I was struggling with same thing for past few hours, your post saved me.

Bill B said...

Thank you, this helped immensely.

HunterSeeker said...

Worked perfectly the first time.

n8n8baby said...

This was great help...thank you very much, sir :)

Rob said...

Strange enough, changing the GroupName didn't work for me. I had three RadioButtons and always the RadioButton tied to the first element in the enum would "stick" to true while the other two RadioButtons worked as expected.

My solution: assigning a starting value of 1 to my first element in the enum.

Try this as an experiment in your code:
- Remove the GroupNames from your buttons.
- Change your enum to the following:

enum Genders
{
Male = 1,
Female
}

Works beautifully for me although I am unsure exactly why. I am assuming that the converter doesn't like emum values that are assigned 0.

(WPF .NET 3.5 C#)

Humanier said...

BTW why don't you just write:

return paramvalue.Equals(value)

instead of:
if (paramvalue.Equals(value))
return true;
else
return false;

Jax said...

Humanier - updated post.

Евгений said...

Thanks, this post was very useful for me!

shawn said...

doesn't it strike you as odd that you can't use the same radio group for what is logically one group of radiobuttons?

Things "freak out" if you use one group because your ConvertBack() is flawed.

Jax said...

Shawn - feel free to offer a correct solution where things don't freak out.