How do I bind RadioButtons to enumeration?

I have an enumeration like this:

public enum MyLovelyEnum
{
    FirstSelection,
    TheOtherSelection,
    YetAnotherOne
};

I get a property in DataContext:

public MyLovelyEnum VeryLovelyEnum { get; set; }

I got three RadioButtons in the WPF client.

<RadioButton Margin="3">First Selection</RadioButton>
<RadioButton Margin="3">The Other Selection</RadioButton>
<RadioButton Margin="3">Yet Another one</RadioButton>

Now, how do I bind RadioButtons to properties for correct two-way binding?

#1 building

Based on Scott's EnumToBooleanConverter. I've noticed that the ConvertBack method doesn't work on enums with flag code.

I tried the following code:

public class EnumHasFlagToBooleanConverter : IValueConverter
    {
        private object _obj;
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            _obj = value;
            return ((Enum)value).HasFlag((Enum)parameter);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value.Equals(true))
            {
                if (((Enum)_obj).HasFlag((Enum)parameter))
                {
                    // Do nothing
                    return Binding.DoNothing;
                }
                else
                {
                    int i = (int)_obj;
                    int ii = (int)parameter;
                    int newInt = i+ii;
                    return (NavigationProjectDates)newInt;
                }
            }
            else
            {
                if (((Enum)_obj).HasFlag((Enum)parameter))
                {
                    int i = (int)_obj;
                    int ii = (int)parameter;
                    int newInt = i-ii;
                    return (NavigationProjectDates)newInt;

                }
                else
                {
                    // do nothing
                    return Binding.DoNothing;
                }
            }
        }
    }

The only thing I couldn't work with was to change the data type from int to targetType so I hardcoded it to the enumeration NavigationProjectDates I used. Also, targetType == NavigationProjectDates

Edit for more generic Flags Enum Converters:

public class FlagsEnumToBooleanConverter : IValueConverter {
        private int _flags=0;
        public object Convert(object value, Type targetType, object parameter, string language) {
            if (value == null) return false;
            _flags = (int) value;
            Type t = value.GetType();
            object o = Enum.ToObject(t, parameter);
            return ((Enum)value).HasFlag((Enum)o);
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            if (value?.Equals(true) ?? false) {
                _flags = _flags | (int) parameter;
            }
            else {
                _flags = _flags & ~(int) parameter;
            }
            return _flags;
        }
    }

#2 building

You can further simplify the answers you accept. You can explicitly pass in enumerations instead of string representations without having to type enumerations as strings in xaml and do unnecessary work in the converter. As CrimsonX commented, errors are thrown at compile time rather than run time:

ConverterParameter = {x: static local: YourEnumType.Enum1}

<StackPanel>
    <StackPanel.Resources>          
        <local:ComparisonConverter x:Key="ComparisonConverter" />          
    </StackPanel.Resources>
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum1}}" />
    <RadioButton IsChecked="{Binding Path=YourEnumProperty, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:YourEnumType.Enum2}}" />
</StackPanel>

Then simplify the converter:

public class ComparisonConverter : 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)
    {
        return value?.Equals(true) == true ? parameter : Binding.DoNothing;
    }
}

Note - NullReferenceException (October 10, 18):

Updated the example to eliminate the possibility of raising a NullReferenceException. IsChecked is a nullable type, so it returns Nullable < Boolean > seems to be a reasonable solution.

Note - multiple sets of RadioButtons in the same container (February 17, 2011):

In xaml, if a radio button shares the same parent container, selecting one deselects all other parent containers in that container, even if they are bound to other properties. Therefore, try putting RadioButtons bound to public properties in their own containers, such as stack panels, and grouping them together. If your related RadioButtons cannot share a single parent container, set the GroupName property of each RadioButton to a common value to logically group them.

Note - enumeration types nested in classes (April 28, 2011):

If your enumeration type is nested in a class (rather than directly in a namespace), you may be able to use "+" syntax to access XAML enumeration if you answer this question in (not marked) Unable to find enumeration type for static reference in WPF :

However, because of this Microsoft Connect questions , the designer in VS2010 will no longer be loaded, indicating that "Type 'local:YourClass+YourNestedEnumType' was not found." cannot find "Type 'local:YourClass+YourNestedEnumType' was not found." however, the project can compile and run successfully. Of course, you can avoid this problem if you can move enumeration types directly to namespaces.

Editor (December 16, 2010):

Thanks to anon for suggesting that you return binding.nothing instead of DependencyProperty.UnsetValue.

Editor (5 May 11):

It simplifies if else of ConvertBack to use ternary operators.

Editor (January 27, 2012):

If the Enum flag is used, the converter will look like this:

public class EnumToBooleanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return ((Enum)value).HasFlag((Enum)parameter); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return value.Equals(true) ? parameter : Binding.DoNothing; } }

Editor (7 may 2015):

If Nullable enumeration (in question Not required, but may be required in some cases, such as when ORM returns null from the database or when the value is not provided in the program logic), remember to add the initial null check in the Convert method and return the appropriate bool value, which is usually false (if you do not want to select any radio button), as follows:

 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value == null) { return false; // or return parameter.Equals(YourEnumType.SomeDefaultValue); } return value.Equals(parameter); }

#3 building

Answer to EnumToBooleanConverter: when the value of IsChecked radio button becomes false, consider returning binding.nothing instead of DependencyProperty.UnsetValue. The former indicates that there is a problem (a red rectangle or similar validation indicator may be displayed to the user), while the latter only indicates that no action should be taken, which is required in this case.

http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.convertback.aspx http://msdn.microsoft.com/en-us/library/system.windows.data.binding .donothing.aspx

#4 building

I'll use RadioButtons in the ListBox and bind it to SelectedValue.

This is an older topic about this topic, but the basic ideas should be the same: http : //social.msdn.microsoft.com/Forums/en-US/wpf/thread/323d067a-efef-4c9f-8d99-fecf45522395/

#5 building

You can use a more general converter

public class EnumBooleanConverter : IValueConverter
{
  #region IValueConverter Members
  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)
        return DependencyProperty.UnsetValue;

    return Enum.Parse(targetType, parameterString);
  }
  #endregion
}

In XAML part, you can use:

<Grid>
    <Grid.Resources>
      <l:EnumBooleanConverter x:Key="enumBooleanConverter" />
    </Grid.Resources>
    <StackPanel >
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=FirstSelection}">first selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=TheOtherSelection}">the other selection</RadioButton>
      <RadioButton IsChecked="{Binding Path=VeryLovelyEnum, Converter={StaticResource enumBooleanConverter}, ConverterParameter=YetAnotherOne}">yet another one</RadioButton>
    </StackPanel>
</Grid>

Tags: Windows Database

Posted on Thu, 06 Feb 2020 22:58:35 -0800 by davestewart