简单的WPF RadioButton绑定?
将一组3个单选button绑定到值为1,2或3的inttypes属性的最简单方法是什么?
实际上,使用像这样的转换器打破了双向绑定,正如我上面所说的,你也不能在枚举中使用它。 更好的方法是使用ListBox的简单样式,如下所示:
注意:与DrWPF.com在他们的例子中所说的相反,不要把ContentPresenter放在RadioButton中,否则如果你添加一个包含诸如button之类的内容的项目,你将不能设置焦点或者与其交互。 这个技术解决了这个问题。 此外,您需要处理文本的灰色以及删除标签上的边距,否则将无法正确呈现。 这种风格也适合你。
<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>
你现在有单选button的外观和感觉,但你可以做双向绑定,你可以使用枚举。 就是这样…
<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>
此外,由于我们明确地分离出了将ListBoxItem进行转换的样式,而不是像其他示例所示的那样将其replace为内联,现在可以创build一个新的样式来根据每个项目(如间距)自定义事件。 (如果您只是尝试将ListBoxItem作为键控样式覆盖generics控件目标,则这将不起作用。)
以下是每个项目上下各有6个保证金的示例。 (请注意,您必须通过ItemContainerStyle属性显式应用样式,而不是简单地按照上述原因在ListBox的资源部分中定位ListBoxItem。)
<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>
希望这有助于,当然,如果你喜欢这个,请标记为接受或投票给我! 🙂
我想出了一个简单的解决scheme。
我有一个model.cs类与:
private int _isSuccess; public int IsSuccess { get { return _isSuccess; } set { _isSuccess = value; } }
我有DataContext设置为model.cs Window1.xaml.cs文件。 xaml包含单选button:
<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" />
这是我的转换器:
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; } }
当然,在Window1的资源中:
<Window.Resources> <local:RadioBoolToIntConverter x:Key="radioBoolToIntConverter" /> </Window.Resources>
我知道这是过时的方式,但我有一个更轻,更简单的替代解决scheme。 从System.Windows.Controls.RadioButton
派生一个类,并声明两个依赖属性RadioValue
和RadioBinding
。 然后在类代码中,重写OnChecked
并将RadioBinding
属性值设置为RadioBinding
属性值的值。 另一方面,使用callback陷阱更改为RadioBinding
属性,并且如果新值等于RadioValue
属性的值,请将其IsChecked
属性设置为true
。
代码如下:
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); } }
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}"/>
希望有人觉得这有用之后:)
我很惊讶没有人提出这种解决scheme来绑定它与布尔arrays。 它可能不是最干净的,但它可以很容易地使用:
private bool[] _modeArray = new bool[] { true, false, false}; public bool[] ModeArray { get { return _modeArray ; } } public int SelectedMode { get { return Array.IndexOf(_modeArray, true); } }
在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}"/>
注意:如果你不想在默认情况下选中,你不需要双向绑定。 双向绑定是这个解决scheme的最大缺点。
优点:
- 不需要代码
- 无需额外的类(IValue转换器)
- 不需要额外的枚举
- 不需要bizzare绑定
- 简单易懂
- 不违反MVVM(呃,至less我希望如此)
有时可以像这样在模型中解决它:假设你有3个布尔型属性OptionA,OptionB,OptionC。
XAML:
<RadioButton IsChecked="{Binding OptionA}"/> <RadioButton IsChecked="{Binding OptionB}"/> <RadioButton IsChecked="{Binding OptionC}"/>
码:
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; } } }
你明白了。 不是最干净的事情,但容易。
这个例子可能看起来有点冗长,但是它的意图应该很清楚。
它在ViewModel中使用3个布尔属性,称为FlagForValue1
, FlagForValue2
和FlagForValue3
。 这三个属性中的每一个都由名为_intValue
的单个私有字段_intValue
。
视图(xaml)的3个单选button每个绑定到视图模型中相应的Flag属性。 这意味着显示“值1”的单选button绑定到视图模型中的FlagForValue1
布尔属性,其他两个相应地绑定。
当在视图模型中设置其中一个属性(例如FlagForValue1
)时,对于其他两个属性(例如FlagForValue2
和FlagForValue3
)也会引发属性更改事件,所以UI(WPF INotifyPropertyChanged
基础结构)可以select/取消select每个单选button正确。
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看起来像这样:
<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>