WPF + MVVM + RadioButton : Handle binding with single property

26,516

Solution 1

You need a converter.

//define this in the Window's Resources section or something similiarly suitable
<local:GenderConverter x:Key="genderConverterKey" />


<RadioButton Content="M" IsChecked="{Binding Gender, Converter={StaticResource ResourceKey=genderConverterKey}, ConverterParameter=M}" />
<RadioButton Content="F" IsChecked="{Binding Gender, Converter={StaticResource ResourceKey=genderConverterKey}, ConverterParameter=F}" />

The converter

public class GenderConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return ((string)parameter == (string)value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (bool)value ? parameter : null;        
    }
}

Replace null (in ConvertBack) with Binding.DoNothing if binding should not be applied in that case.

return (bool)value ? parameter : Binding.DoNothing;

Solution 2

Use Commands (Using DelegateCommands here)

VM:

public enum Genders {
    Female,
    Male
}
public YourVMClass {
    public Genders SelectedGender {get; set;}

    private DelegateCommand _cmdSelectGender;

    public DelegateCommand CmdSelectGender {
        get { return _cmdSelectGender ?? (_cmdSelectGender = new DelegateCommand(SelectGender)); }
    }

    private void SelectGender(Object parameter) {
        SelectedGender = (Genders)parameter;
    }
}

XAML:

<Window.Resources>
    <ObjectDataProvider x:Key="listOfGenders" MethodName="GetValues"
                        ObjectType="{x:Type System:Enum}">
        <ObjectDataProvider.MethodParameters>
            <x:Type TypeName="loca:Genders"/>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

<ItemsControl ItemsSource="{Binding Source={StaticResources listOfGenders}}">
    <ItemsControl.ItemTemplate>
        <RadioButton GroupName="Genders" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MainWindow}}, Path=DataContext.CmdSelectGender}" CommandParameter="{Binding}"/>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

(Didn't test the code, but this is the idea)

Solution 3

Your requirement is possible, but you would need some additional effort to make it work. The main reason for this is RadioButton’s property IsChecked is Boolean and multiple radio buttons are separate controls and doesn’t act like one. For example a ListBox.

For your requirement to work, you could use a Converter. Bind the IsChecked of both Radiobuttons to the PersonGender property in ViewModel and use a common converter and pass a parameter ‘MALE’ for male radio button and ’FEMALE’ for female radio button.

In Converter check if parameter and PersonGender are same and return TRUE for that.

Ie. If checkbox command parameter is MALE and PersonGender is also MALE, then the checkbox is enabled Else if checkbox command parameter is FEMALE and PersonGender is MALE, checkbox is not enabled since false is returned.

Share:
26,516
Amit Joshi
Author by

Amit Joshi

I am working as Dot Net developer (actually multiple Microsoft technologies including SQL Server, IIS etc.) since 2004. My domain is medical imaging and healthcare.

Updated on October 26, 2021

Comments

  • Amit Joshi
    Amit Joshi over 2 years

    From this and this (and other) questions on SO and many other material on internet, I understood how to bind radio button with VM.

    But all of them create separate property for each possible value of radio button. One question (this) is similar to my requirement but the accepted answer suggests to use ListBox instead of radio button.

    To represent person gender (Datatype CHAR, Possible values 'M', 'F'), three properties needs to be created in VM as PersonGender, IsPersonMale, IsPersonFemale. I want to control this on only one property PersonGender. Can I do this? If yes, how?

  • Amit Joshi
    Amit Joshi almost 8 years
    Replace null (in ConvertBack) with Binding.DoNothing if binding should not be applied in that case. return (bool)value ? parameter : Binding.DoNothing;
  • Peter M
    Peter M over 6 years
    There is nothing in the converter that actually ties it to Gender data type. So you could rename it to make it a general purpose converter.
  • Kim Homann
    Kim Homann over 3 years
    For my taste, this solution is purer MVVM than the commands solution.