47
votes

I have a property of type boolean presented with checkbox.

I want to change that to two radiobuttons that bind on the same property presenting the value true/false.

How can that be done?

8

8 Answers

86
votes
<RadioButton GroupName="Group1" 
             IsChecked="{Binding PropertyValue}" Content="Yes" />
<RadioButton GroupName="Group1"  Content="No" 
             IsChecked="{Binding PropertyValue, 
                         Converter={StaticResource BoolInverterConverter}}" />
public class BoolInverterConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter,
        System.Globalization.CultureInfo culture)
    {
        if (value is bool)
        {
            return !(bool)value;
        }
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
        System.Globalization.CultureInfo culture)
    {
        if (value is bool)
        {
            return !(bool)value;
        }
        return value;
    }

    #endregion
}
17
votes

The standard binding approach has the unfortunate side effect of firing the binding setter as "unselected" whenever the UI is loaded. So if you've got code to handle the user's clicks in the setter for your bool, it will do some weird stuff like fire the setter to "false" even though you've bound it to a "true" bool.

I got around this with a converter used specifically for radio buttons:

public class BoolRadioConverter : IValueConverter
{
    public bool Inverse { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool boolValue = (bool) value;

        return this.Inverse ? !boolValue : boolValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool boolValue = (bool)value;

        if (!boolValue)
        {
            // We only care when the user clicks a radio button to select it.
            return null;
        }

        return !this.Inverse;
    }
}

In your resources:

<converters:BoolRadioConverter x:Key="BoolRadioConverter" />
<converters:BoolRadioConverter x:Key="InverseBoolRadioConverter" Inverse="True" />

In your xaml:

<RadioButton
    Content="True option"
    GroupName="radioGroup1"
    IsChecked="{Binding MyProperty,
                        Converter={StaticResource BoolRadioConverter}}" />
<RadioButton
    Content="False option"
    GroupName="radioGroup2"
    IsChecked="{Binding MyProperty,
                        Converter={StaticResource InverseBoolRadioConverter}}" />
9
votes

You can use a value-converter that reverts the boolean value:

With that converter, bind one Checkbox.IsChecked-property to the boolean value without the converter and one CheckBox.IsChecked-property with the converter. This should do the trick.

Here the code for such a converter. I have copied it from here and added some lines of code. There you will find more information about.

public class BoolToOppositeBoolConverter : IValueConverter {
    public object Convert(object value, Type targetType, object parameter,System.Globalization.CultureInfo culture) {
        if (targetType != typeof(bool)) {
            throw new InvalidOperationException("The target must be a boolean");
        }
        if (null == value) {
            return null;
        }
                    return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter,System.Globalization.CultureInfo culture) {
        if (targetType != typeof(bool)) {
            throw new InvalidOperationException("The target must be a boolean");
        }
        if (null == value) {
            return null;
        }
        return !(bool)value;
    }
} 

To use it, declare it in the resource-section.

 <local:BoolToOppositeBoolConverter x:Key="BoolToOppositeBoolConverter_ValueConverter"/>

And the use it in the binding as a static resource:

<CheckBox IsChecked="{Binding YourProperty}" />
<CheckBox IsChecked="{Binding YourProperty,Converter={StaticResource BoolToOppositeBoolConverter_ValueConverter}}" />

Please note, the converter is only a simple example. Implement it neatly if you want to use it in productive code. I have not tested it. Make a comment if its not working.

4
votes

You can achieve this without a converter if you set the GroupName property of two radio button to the same value (so only one can be checked at the time). Then, set IsChecked of one radio button to "True", and bind IsChecked of another to your Boolean. Switching radio buttons will change the Boolean value, however, changing the Boolean value to False will not check the other radio button.

Thanks, Vlad

3
votes

Here is the solution on how to bind radio buttons to any type (enumeration, Boolean, string, integer, etc.) with the sample code:

http://www.codeproject.com/Tips/720497/Binding-Radio-Buttons-to-a-Single-Property

2
votes

When using MVVMLight and DataContext is set in XAML as:

DataContext="{Binding <Your ViewModel property name>, Source={StaticResource Locator}}" 

BoolInverterConverter causes Stack Overflow second time the window gets opened.

The work around is to remove DataContext from XAML and do it in code in window constructor after InitializeComponent():

DataContext = ServiceLocator.Current.GetInstance<Your View Model class>();

After some testing it was not enough - Stack Overflow error could pop up randomly when clicking on radio button. The solution which worked for me - instead of the converter use another property for other radio button in a group:

public bool Is9to1 { get; set; }
public bool Is1to9 { get { return !Is9to1; } set { Is9to1 = !value; } } 

in XAML:

   <RadioButton GroupName="Is9to1" IsChecked="{Binding Is1to9}"/>
   <RadioButton GroupName="Is9to1" IsChecked="{Binding Is9to1}"/>
0
votes

Simplified version of ragunathan's answer.

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) =>
    Convert(value);

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) =>
    Convert(value);

private object Convert(object value) => 
    value is bool ? !(bool)value : value;
0
votes

Little upgrade of RandomEngy's answer if you want your bool nullable (for no default value/Checked Radiobutton)

public class BoolRadioConverter : IValueConverter
{
    public bool Inverse { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool? boolValue = (bool?)value;

        return this.Inverse ? !boolValue : boolValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool? boolValue = (bool?)value;

        if (boolValue != null && (bool)!boolValue)
        {
            // We only care when the user clicks a radio button to select it.
            return null;
        }

        return !this.Inverse;
    }
}

and the rest is the same as his answer.