8
  • I'm having few RadioButtons and I don't want to bind "IsChecked" property of each one of them to unique property in the code.
  • I want to have a single property like "CurrentSelected" and according to that to set the "IsChecked".
  • In addition I don't want to use converters.
  • I tried to use the behavior "ChangePropertyAction" but it looks like it's working only in one way. here is my code:

    <RadioButton
        x:Name="UpRadioButton"
        Margin="5"
        Content="Up"
        >
        <i:Interaction.Triggers>
            <ei:DataTrigger Binding="{Binding IsChecked, ElementName=UpRadioButton}" Value="True">
                <ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="SelectedDirection" Value="{x:Static Enums:DirectionEnum.Up}" />
            </ei:DataTrigger>
        </i:Interaction.Triggers>
    </RadioButton>
    
    <RadioButton
        x:Name="DownRadioButton"
        Margin="5"
        Content="Down"
        >
        <i:Interaction.Triggers>
            <ei:DataTrigger Binding="{Binding IsChecked, ElementName=DownRadioButton}" Value="True">
                <ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="SelectedDirection" Value="{x:Static Enums:DirectionEnum.Down}" />
            </ei:DataTrigger>
        </i:Interaction.Triggers>
    </RadioButton>
    
    <RadioButton
        x:Name="LeftRadioButton"
        Margin="5"
        Content="Left"
        >
        <i:Interaction.Triggers>
            <ei:DataTrigger Binding="{Binding IsChecked, ElementName=LeftRadioButton}" Value="True">
                <ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="SelectedDirection" Value="{x:Static Enums:DirectionEnum.Left}" />
            </ei:DataTrigger>
        </i:Interaction.Triggers>
    </RadioButton>
    
    <RadioButton
        x:Name="RightRadioButton"
        Margin="5"
        Content="Right"
        >
        <i:Interaction.Triggers>
            <ei:DataTrigger Binding="{Binding IsChecked, ElementName=RightRadioButton}" Value="True">
                <ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="SelectedDirection" Value="{x:Static Enums:DirectionEnum.Right}" />
            </ei:DataTrigger>
        </i:Interaction.Triggers>
    </RadioButton>               
    

my view model is very simple: MainViewModel.cs

public class MainViewModel : ViewModelBase
{ 
    private DirectionEnum _selectedDirection;

    public DirectionEnum SelectedDirection
    {
        get { return _selectedDirection; }
        set
        {
            if (_selectedDirection != value)
            {
                _selectedDirection = value;
                RaisePropertyChanged();
            }
        }
    }
    public MainViewModel()
    {     
        SelectedDirection = DirectionEnum.Up;            
    }  
}

as you can see from the code, the "Up" RadioButton should be already checked... What am I missing ?

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
kaycee
  • 1,199
  • 4
  • 24
  • 42
  • 1
    It might only be working one way since your bindings are only one way... Also, whats wrong with converters? There's one that is *great* for this – BradleyDotNET Feb 17 '15 at 21:25
  • converters require maintenance... – kaycee Feb 17 '15 at 21:37
  • So does code in general... Its your choice, but saying that you don't like converters because they require "maintenance" is a pretty poor reason/excuse in my book. – BradleyDotNET Feb 17 '15 at 21:39
  • Bradley, please refer in the solution Rachel advised.don't you think it's more elegant way then holding 2 way converter ? – kaycee Feb 17 '15 at 21:42
  • Do I *personally* think that it's more elegant? No. For dynamic data, I could see it, but if you know your radio button's data from the start, a `ValueEqualsConverter` is *extremely* elegant/easy. – BradleyDotNET Feb 17 '15 at 21:44

1 Answers1

16

A common solution for me is to use a ListBox, which contains Selection behavior, and overwrite the Template to draw items as RadioButtons instead.

My XAML template usually looks something like this :

<Style x:Key="RadioButtonListBoxStyle" TargetType="{x:Type ListBox}">
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Cycle" />
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="{x:Type ListBoxItem}" >
                <Setter Property="Margin" Value="2, 2, 2, 0" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border Background="Transparent">
                                <RadioButton
                                    Content="{TemplateBinding ContentPresenter.Content}" VerticalAlignment="Center"
                                    IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>

                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

The style is applied like this:

<ListBox ItemsSource="{Binding Directions}"
         SelectedValue="{Binding SelectedDirection}"
         Style="{StaticResource RadioButtonListBoxStyle}" />

I find this much cleaner for managing selection behavior of grouped RadioButtons than maintaining a lot of IsChecked properties in my code-behind, or using converters.

Rachel
  • 130,264
  • 66
  • 304
  • 490
  • 1
    Rachel, Your solution is more than perfect. Thanks – kaycee Feb 17 '15 at 21:35
  • 1
    After trying to make this work for a while I finally found your other post which explains why it doesn't work with `DisplayMemberPath` - https://stackoverflow.com/a/7487670/3195477 So glad you updated that one too! – StayOnTarget Feb 18 '20 at 22:55