Simple WPF RadioButton Binding?

What is the easiest way to bind a group of three radio objects to an int type property for values ​​1, 2, or 3?

+49
radio-button wpf binding
Aug 23 '09 at 6:03
source share
8 answers

In fact, using such a converter violates two-way binding, plus, as I said above, you cannot use this with enumerations either. The best way to do this is to use a simple style for the ListBox, like so:

Note. Contrary to what DrWPF.com pointed out in its example, do not put ContentPresenter in RadioButton, otherwise, if you add an element with content such as a button or something else, you cannot set focus or interact with it. This technique solves this is. In addition, you need to process gray text, as well as delete fields on labels, otherwise it will not display correctly. This style is also suitable for you.

<Style x:Key="RadioButtonListItem" TargetType="{x:Type ListBoxItem}" > <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBoxItem"> <DockPanel LastChildFill="True" Background="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Center" > <RadioButton IsChecked="{TemplateBinding IsSelected}" Focusable="False" IsHitTestVisible="False" VerticalAlignment="Center" Margin="0,0,4,0" /> <ContentPresenter Content = "{TemplateBinding ContentControl.Content}" ContentTemplate = "{TemplateBinding ContentControl.ContentTemplate}" ContentStringFormat = "{TemplateBinding ContentControl.ContentStringFormat}" HorizontalAlignment = "{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment = "{TemplateBinding Control.VerticalContentAlignment}" SnapsToDevicePixels = "{TemplateBinding UIElement.SnapsToDevicePixels}" /> </DockPanel> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style x:Key="RadioButtonList" TargetType="ListBox"> <Style.Resources> <Style TargetType="Label"> <Setter Property="Padding" Value="0" /> </Style> </Style.Resources> <Setter Property="BorderThickness" Value="0" /> <Setter Property="Background" Value="Transparent" /> <Setter Property="ItemContainerStyle" Value="{StaticResource RadioButtonListItem}" /> <Setter Property="Control.Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBox}"> <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="IsEnabled" Value="False"> <Setter Property="TextBlock.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" /> </Trigger> </Style.Triggers> </Style> <Style x:Key="HorizontalRadioButtonList" BasedOn="{StaticResource RadioButtonList}" TargetType="ListBox"> <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <VirtualizingStackPanel Background="Transparent" Orientation="Horizontal" /> </ItemsPanelTemplate> </Setter.Value> </Setter> </Style> 

Now you have the appearance of the switches, but you can do two-way binding and use an enumeration. Here's how ...

 <ListBox Style="{StaticResource RadioButtonList}" SelectedValue="{Binding SomeVal}" SelectedValuePath="Tag"> <ListBoxItem Tag="{x:Static l:MyEnum.SomeOption}" >Some option</ListBoxItem> <ListBoxItem Tag="{x:Static l:MyEnum.SomeOtherOption}">Some other option</ListBoxItem> <ListBoxItem Tag="{x:Static l:MyEnum.YetAnother}" >Yet another option</ListBoxItem> </ListBox> 

In addition, since we explicitly separated the style that ListBoxItem tracks, rather than putting it in a row, again, as other examples showed, now you can create a new style for it to customize elements for each element, such as spacing. (This will not work if you just try to target ListBoxItem, as the key style overrides the overall management goals.)

Here is an example of placing field 6 above and below each element. (Note how you should explicitly apply a style through the ItemContainerStyle property, and not just target it with a ListBoxItem in the ListBox resource section for the reason mentioned above.)

 <Window.Resources> <Style x:Key="SpacedRadioButtonListItem" TargetType="ListBoxItem" BasedOn="{StaticResource RadioButtonListItem}"> <Setter Property="Margin" Value="0,6" /> </Style> </Window.Resources> <ListBox Style="{StaticResource RadioButtonList}" ItemContainerStyle="{StaticResource SpacedRadioButtonListItem}" SelectedValue="{Binding SomeVal}" SelectedValuePath="Tag"> <ListBoxItem Tag="{x:Static l:MyEnum.SomeOption}" >Some option</ListBoxItem> <ListBoxItem Tag="{x:Static l:MyEnum.SomeOtherOption}">Some other option</ListBoxItem> <ListBoxItem Tag="{x:Static l:MyEnum.YetAnother}" >Ter another option</ListBoxItem> </ListBox> 
+32
Nov 07 2018-10-11T00:
source share

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 a Window1.xaml.cs file with a DataContext set to model.cs. Xaml contains radio objects:

 <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 resources:

 <Window.Resources> <local:RadioBoolToIntConverter x:Key="radioBoolToIntConverter" /> </Window.Resources> 
+81
Sep 01 '09 at 3:44
source share

I am very surprised that no one came up with such a solution to associate it with a bool array. It may 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 do not need two-way binding if you do not want the checkbox selected by default. TwoWay binding is the biggest drawback of this solution.

Pros:

  • No need to write code
  • No need for an extra class (IValue converter)
  • No need for additional transfers
  • does not require bizzare binding
  • simple and straightforward
  • does not violate MVVM (heh, at least I hope)
+25
Jun 11 '14 at 15:17
source share

I know this is expired, but I have an alternative solution that is easier and simpler. Derive the class from System.Windows.Controls.RadioButton and declare two properties of the RadioValue and RadioBinding . Then, in the class code, override OnChecked and set the value of the RadioBinding property to the value of the RadioValue property. In the other direction, the trap enters the RadioBinding property with a callback, and if the new value is equal to the value of the RadioValue property, set its IsChecked property to true .

Here is 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); } } 

Using XAML:

 <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 helpful after all this time :)

+16
Apr 10 '13 at
source share

Sometimes this can be solved in the model as follows: 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.

+1
Feb 11 '16 at 14:28
source share

This example may seem a little long, but its intent should be clear enough.

It uses 3 boolean properties in the called ViewModel, FlagForValue1 , FlagForValue2 and FlagForValue3 . Each of these 3 properties is supported by one private field called _intValue .

3 radio buttons of the form (xaml) are attached to the corresponding Flag property in the presentation model. This means that the switch displaying the value "1" is tied to the FlagForValue1 bool property in the view model and two others accordingly.

When setting one of the properties in the view model (for example, FlagForValue1 ), it is also important to increase the properties of the changed events for the other two properties (for example, FlagForValue2 and FlagForValue3 ), so the user interface (WPF INotifyPropertyChanged ) can correctly select / deselect each switch.

  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"); } } 

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> 
0
Jul 23 '15 at 7:25
source share

I came up with a solution using Binding.DoNothing returned by the converter that does not break the 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(); } } 

Using:

 <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> 
0
Feb 26 '18 at 7:46
source share

I created an attached property based on Aviad Answer that does not 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); } } } 

using:

 <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}"/> 
0
Jun 26 '19 at 17:27
source share



All Articles