[wpf] Simple WPF RadioButton Binding?

What is the simplest way to bind a group of 3 radiobuttons to a property of type int for values 1, 2, or 3?

This question is related to wpf binding radio-button

The answer is


I've come up with solution using Binding.DoNothing returned from converter which doesn't break two-way binding.

public class EnumToCheckedConverter : IValueConverter
{
    public Type Type { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null && value.GetType() == Type)
        {
            try
            {
                var parameterFlag = Enum.Parse(Type, parameter as string);

                if (Equals(parameterFlag, value))
                {
                    return true;
                }
            }
            catch (ArgumentNullException)
            {
                return false;
            }
            catch (ArgumentException)
            {
                throw new NotSupportedException();
            }

            return false;
        }
        else if (value == null)
        {
            return false;
        }

        throw new NotSupportedException();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null && value is bool check)
        {
            if (check)
            {
                try
                {
                    return Enum.Parse(Type, parameter as string);
                }
                catch(ArgumentNullException)
                {
                    return Binding.DoNothing;
                }
                catch(ArgumentException)
                {
                    return Binding.DoNothing;
                }
            }

            return Binding.DoNothing;
        }

        throw new NotSupportedException();
    }
}

Usage:

<converters:EnumToCheckedConverter x:Key="SourceConverter" Type="{x:Type monitor:VariableValueSource}" />

Radio button bindings:

<RadioButton GroupName="ValueSource" 
             IsChecked="{Binding Source, Converter={StaticResource SourceConverter}, ConverterParameter=Function}">Function</RadioButton>

Sometimes it is possible to solve it in the model like this: Suppose you have 3 boolean properties OptionA, OptionB, OptionC.

XAML:

<RadioButton IsChecked="{Binding OptionA}"/>
<RadioButton IsChecked="{Binding OptionB}"/>
<RadioButton IsChecked="{Binding OptionC}"/>

CODE:

private bool _optionA;
public bool OptionA
{
    get { return _optionA; }
    set
    {
        _optionA = value;
        if( _optionA )
        {
             this.OptionB= false;
             this.OptionC = false;
        }
    }
}

private bool _optionB;
public bool OptionB
{
    get { return _optionB; }
    set
    {
        _optionB = value;
        if( _optionB )
        {
            this.OptionA= false;
            this.OptionC = false;
        }
    }
}

private bool _optionC;
public bool OptionC
{
    get { return _optionC; }
    set
    {
        _optionC = value;
        if( _optionC )
        {
            this.OptionA= false;
            this.OptionB = false;
        }
    }
}

You get the idea. Not the cleanest thing, but easy.


I created an attached property based on Aviad's Answer which doesn't require creating a new class

public static class RadioButtonHelper
{
    [AttachedPropertyBrowsableForType(typeof(RadioButton))]
    public static object GetRadioValue(DependencyObject obj) => obj.GetValue(RadioValueProperty);
    public static void SetRadioValue(DependencyObject obj, object value) => obj.SetValue(RadioValueProperty, value);
    public static readonly DependencyProperty RadioValueProperty =
        DependencyProperty.RegisterAttached("RadioValue", typeof(object), typeof(RadioButtonHelper), new PropertyMetadata(new PropertyChangedCallback(OnRadioValueChanged)));

    private static void OnRadioValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is RadioButton rb)
        {
            rb.Checked -= OnChecked;
            rb.Checked += OnChecked;
        }
    }

    public static void OnChecked(object sender, RoutedEventArgs e)
    {
        if (sender is RadioButton rb)
        {
            rb.SetCurrentValue(RadioBindingProperty, rb.GetValue(RadioValueProperty));
        }
    }

    [AttachedPropertyBrowsableForType(typeof(RadioButton))]
    public static object GetRadioBinding(DependencyObject obj) => obj.GetValue(RadioBindingProperty);
    public static void SetRadioBinding(DependencyObject obj, object value) => obj.SetValue(RadioBindingProperty, value);

    public static readonly DependencyProperty RadioBindingProperty =
        DependencyProperty.RegisterAttached("RadioBinding", typeof(object), typeof(RadioButtonHelper), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnRadioBindingChanged)));

    private static void OnRadioBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is RadioButton rb && rb.GetValue(RadioValueProperty).Equals(e.NewValue))
        {
            rb.SetCurrentValue(RadioButton.IsCheckedProperty, true);
        }
    }
}

usage :

<RadioButton GroupName="grp1" Content="Value 1"
    helpers:RadioButtonHelper.RadioValue="val1" helpers:RadioButtonHelper.RadioBinding="{Binding SelectedValue}"/>
<RadioButton GroupName="grp1" Content="Value 2"
    helpers:RadioButtonHelper.RadioValue="val2" helpers:RadioButtonHelper.RadioBinding="{Binding SelectedValue}"/>
<RadioButton GroupName="grp1" Content="Value 3"
    helpers:RadioButtonHelper.RadioValue="val3" helpers:RadioButtonHelper.RadioBinding="{Binding SelectedValue}"/>
<RadioButton GroupName="grp1" Content="Value 4"
    helpers:RadioButtonHelper.RadioValue="val4" helpers:RadioButtonHelper.RadioBinding="{Binding SelectedValue}"/>

This example might be seem a bit lengthy, but its intention should be quite clear.

It uses 3 Boolean properties in the ViewModel called, FlagForValue1, FlagForValue2 and FlagForValue3. Each of these 3 properties is backed by a single private field called _intValue.

The 3 Radio buttons of the view (xaml) are each bound to its corresponding Flag property in the view model. This means the radio button displaying "Value 1" is bound to the FlagForValue1 bool property in the view model and the other two accordingly.

When setting one of the properties in the view model (e.g. FlagForValue1), its important to also raise property changed events for the other two properties (e.g. FlagForValue2, and FlagForValue3) so the UI (WPF INotifyPropertyChanged infrastructure) can selected / deselect each radio button correctly.

    private int _intValue;

    public bool FlagForValue1
    {
        get
        {
            return (_intValue == 1) ? true : false;
        }
        set
        {
            _intValue = 1;
            RaisePropertyChanged("FlagForValue1");
            RaisePropertyChanged("FlagForValue2");
            RaisePropertyChanged("FlagForValue3");
        }
    }

    public bool FlagForValue2
    {
        get
        {
            return (_intValue == 2) ? true : false;
        }
        set
        {
            _intValue = 2;
            RaisePropertyChanged("FlagForValue1");
            RaisePropertyChanged("FlagForValue2");
            RaisePropertyChanged("FlagForValue3");
        }
    }

    public bool FlagForValue3
    {
        get
        {
            return (_intValue == 3) ? true : false;
        }
        set
        {
            _intValue = 3;
            RaisePropertyChanged("FlagForValue1");
            RaisePropertyChanged("FlagForValue2");
            RaisePropertyChanged("FlagForValue3");
        }
    }

The xaml looks like this:

                <RadioButton GroupName="Search" IsChecked="{Binding Path=FlagForValue1, Mode=TwoWay}"
                             >Value 1</RadioButton>

                <RadioButton GroupName="Search" IsChecked="{Binding Path=FlagForValue2, Mode=TwoWay}"
                             >Value 2</RadioButton>

                <RadioButton GroupName="Search" IsChecked="{Binding Path=FlagForValue3, Mode=TwoWay}"
                             >Value 3</RadioButton>

I know it's way way overdue, but I have an alternative solution, which is lighter and simpler. Derive a class from System.Windows.Controls.RadioButton and declare two dependency properties RadioValue and RadioBinding. Then in the class code, override OnChecked and set the RadioBinding property value to that of the RadioValue property value. In the other direction, trap changes to the RadioBinding property using a callback, and if the new value is equal to the value of the RadioValue property, set its IsChecked property to true.

Here's the code:

public class MyRadioButton : RadioButton
{
    public object RadioValue
    {
        get { return (object)GetValue(RadioValueProperty); }
        set { SetValue(RadioValueProperty, value); }
    }

    // Using a DependencyProperty as the backing store for RadioValue.
       This enables animation, styling, binding, etc...
    public static readonly DependencyProperty RadioValueProperty =
        DependencyProperty.Register(
            "RadioValue", 
            typeof(object), 
            typeof(MyRadioButton), 
            new UIPropertyMetadata(null));

    public object RadioBinding
    {
        get { return (object)GetValue(RadioBindingProperty); }
        set { SetValue(RadioBindingProperty, value); }
    }

    // Using a DependencyProperty as the backing store for RadioBinding.
       This enables animation, styling, binding, etc...
    public static readonly DependencyProperty RadioBindingProperty =
        DependencyProperty.Register(
            "RadioBinding", 
            typeof(object), 
            typeof(MyRadioButton), 
            new FrameworkPropertyMetadata(
                null, 
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
                OnRadioBindingChanged));

    private static void OnRadioBindingChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        MyRadioButton rb = (MyRadioButton)d;
        if (rb.RadioValue.Equals(e.NewValue))
            rb.SetCurrentValue(RadioButton.IsCheckedProperty, true);
    }

    protected override void OnChecked(RoutedEventArgs e)
    {
        base.OnChecked(e);
        SetCurrentValue(RadioBindingProperty, RadioValue);
    }
}

XAML usage:

<my:MyRadioButton GroupName="grp1" Content="Value 1"
    RadioValue="val1" RadioBinding="{Binding SelectedValue}"/>
<my:MyRadioButton GroupName="grp1" Content="Value 2"
    RadioValue="val2" RadioBinding="{Binding SelectedValue}"/>
<my:MyRadioButton GroupName="grp1" Content="Value 3"
    RadioValue="val3" RadioBinding="{Binding SelectedValue}"/>
<my:MyRadioButton GroupName="grp1" Content="Value 4"
    RadioValue="val4" RadioBinding="{Binding SelectedValue}"/>

Hope someone finds this useful after all this time :)


I am very suprised nobody came up with this kind of solution to bind it against bool array. It might not be the cleanest, but it can be used very easily:

private bool[] _modeArray = new bool[] { true, false, false};
public bool[] ModeArray
{
    get { return _modeArray ; }
}
public int SelectedMode
{
    get { return Array.IndexOf(_modeArray, true); }
}

in XAML:

<RadioButton GroupName="Mode" IsChecked="{Binding Path=ModeArray[0], Mode=TwoWay}"/>
<RadioButton GroupName="Mode" IsChecked="{Binding Path=ModeArray[1], Mode=TwoWay}"/>
<RadioButton GroupName="Mode" IsChecked="{Binding Path=ModeArray[2], Mode=TwoWay}"/>

NOTE: you dont need two-way binding if you dont want to one checked by default. TwoWay binding is the biggest cons of this solution.

Pros:

  • No need for code behind
  • No need for extra class (IValue Converter)
  • No Need for extra enums
  • doesnt require bizzare binding
  • straightforward and easy to understand
  • doesnt violate MVVM (heh, at least I hope so)

I came up with a simple solution.

I have a model.cs class with:

private int _isSuccess;
public int IsSuccess { get { return _isSuccess; } set { _isSuccess = value; } }

I have Window1.xaml.cs file with DataContext set to model.cs. The xaml contains the radiobuttons:

<RadioButton IsChecked="{Binding Path=IsSuccess, Converter={StaticResource radioBoolToIntConverter}, ConverterParameter=1}" Content="one" />
<RadioButton IsChecked="{Binding Path=IsSuccess, Converter={StaticResource radioBoolToIntConverter}, ConverterParameter=2}" Content="two" />
<RadioButton IsChecked="{Binding Path=IsSuccess, Converter={StaticResource radioBoolToIntConverter}, ConverterParameter=3}" Content="three" />

Here is my converter:

public class RadioBoolToIntConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int integer = (int)value;
        if (integer==int.Parse(parameter.ToString()))
            return true;
        else
            return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return parameter;
    }
}

And of course, in Window1's resources:

<Window.Resources>
    <local:RadioBoolToIntConverter x:Key="radioBoolToIntConverter" />
</Window.Resources>

Examples related to wpf

Error: the entity type requires a primary key Reportviewer tool missing in visual studio 2017 RC Pass command parameter to method in ViewModel in WPF? Calling async method on button click Setting DataContext in XAML in WPF How to resolve this System.IO.FileNotFoundException System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll? Binding an Image in WPF MVVM How to bind DataTable to Datagrid Setting cursor at the end of any text of a textbox

Examples related to binding

Binding ComboBox SelectedItem using MVVM Binding List<T> to DataGridView in WinForm Angularjs Template Default Value if Binding Null / Undefined (With Filter) Bootstrap control with multiple "data-toggle" How does the 'binding' attribute work in JSF? When and how should it be used? WPF Binding to parent DataContext How to get evaluated attributes inside a custom directive How can I use a C++ library from node.js? bind/unbind service example (android) Datagrid binding in WPF

Examples related to radio-button

Angular 4 default radio button checked by default Angular2 - Radio Button Binding Detect if a Form Control option button is selected in VBA How to create radio buttons and checkbox in swift (iOS)? How to check if a radiobutton is checked in a radiogroup in Android? Radio Buttons ng-checked with ng-model Multiple radio button groups in MVC 4 Razor Show div when radio button selected Check a radio button with javascript Bootstrap radio button "checked" flag