Search code examples
c#.netwpfdata-binding

Returning a Nullable Bool from Converter to XAML


I have a group of three Radio Buttons bound to a nullable bool. I have the converters written, but I'm not sure how to write the ConvertBack? When I open the window, multiple options of the group are selected.

Converter class:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    switch ((string)parameter)
    {
        case "Pass":
            return true;
        case "Fail":
            return false;
        case "NotComplete":
            return null;
        default:
            return null;
    }
}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    switch ((bool?)value)
    {
        case true:
            return "Pass";
        case false:
            return "Fail";
        case null:
            return "NotComplete";
        default:
            return "NotComplete";
    }
}

RadioButtons in XAML:

<RadioButton GroupName="GroupOneRadioButton" IsEnabled="{Binding CanPassGroupOneTest}" IsChecked="{Binding GroupOneTestResult, Converter={StaticResource radioButtonConverter}, ConverterParameter=Pass}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" />
<RadioButton GroupName="GroupOneRadioButton" IsEnabled="{Binding CanPassGroupOneTest}" IsChecked="{Binding GroupOneTestResult, Converter={StaticResource radioButtonConverter}, ConverterParameter=Fail}"  Grid.Row="1" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" />
<RadioButton GroupName="GroupOneRadioButton" IsEnabled="{Binding CanPassGroupOneTest}" IsChecked="{Binding GroupOneTestResult, Converter={StaticResource radioButtonConverter}, ConverterParameter=NotComplete}"  Grid.Row="1" Grid.Column="3" HorizontalAlignment="Center" VerticalAlignment="Center" />

More details:

Apologies for being unclear at the beginning. Hopefully this explains:

  • GroupOneTestResult is a Nullable boolean, defined as:

    public bool? GroupOneTestResult { get; set; }

  • In the XAML are three radio buttons - Pass, Failed, Not Complete, which as a group I want to bind to GroupOneTestResult (button one, pass, binds to True. Button two, fail, binds to false. Button three, Not Complete, binds to null)

  • When the button in the group is clicked in the XAML, the correct value needs to be stored in GroupOneTestResult

  • GroupOneTestResult needs to be changed programatically (for example, when a test result is loaded) and this value being reflected by the automatically selected RadioButton.

  • I have the Converter class which, in my first attempt, would take ConverterParameter from the XAML and get the correct boolean value. This is not working. I'm not sure how to do the above.


Solution

  • Binding multiple RadioButtons in a group to a single property requires special handling in the Binding Converter.

    The ConvertBack method should only return a value when a RadioButton was checked, to avoid that automatic unchecking of the others will have any further effect.

    Besides that, the Convert method must compare the passed value to the three possible values according to the parameter string.

    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch ((string)parameter)
        {
            case "Pass":
                return (bool?)value == true;
            case "Fail":
                return (bool?)value == false;
            default:
                return (bool?)value == null;
        }
    }
    
    public object ConvertBack(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        if ((bool)value)
        {
            switch ((string)parameter)
            {
                case "Pass":
                    return (bool?)true;
                case "Fail":
                    return (bool?)false;
                default:
                    return (bool?)null;
             }
        }
    
        return Binding.DoNothing;
    }