我有一个布尔类型的属性,用复选框表示。
我想将其更改为两个单选按钮,绑定在同一属性上,分别表示 true/false 的值。
如何实现?
我有一个布尔类型的属性,用复选框表示。
我想将其更改为两个单选按钮,绑定在同一属性上,分别表示 true/false 的值。
如何实现?
<RadioButton GroupName="Group1"
IsChecked="{Binding PropertyValue}" Content="Yes" />
<RadioButton GroupName="Group1" Content="No"
IsChecked="{Binding PropertyValue,
Converter={StaticResource BoolInverterConverter}}" />
public class BoolInverterConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return !(bool)value;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return !(bool)value;
}
return value;
}
#endregion
}
标准绑定方法的不幸副作用是每当UI被加载时,会触发绑定setter为"未选择"。因此,如果您有处理用户在bool setter中点击的代码,它将做一些奇怪的事情,例如触发setter为“false”,即使您已将其绑定到“true”的bool。
我通过专门用于单选按钮的转换器解决了这个问题:
public class BoolRadioConverter : IValueConverter
{
public bool Inverse { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool boolValue = (bool) value;
return this.Inverse ? !boolValue : boolValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool boolValue = (bool)value;
if (!boolValue)
{
// We only care when the user clicks a radio button to select it.
return null;
}
return !this.Inverse;
}
}
在您的资源中:
<converters:BoolRadioConverter x:Key="BoolRadioConverter" />
<converters:BoolRadioConverter x:Key="InverseBoolRadioConverter" Inverse="True" />
在你的 XAML 中:
<RadioButton
Content="True option"
GroupName="radioGroup1"
IsChecked="{Binding MyProperty,
Converter={StaticResource BoolRadioConverter}}" />
<RadioButton
Content="False option"
GroupName="radioGroup2"
IsChecked="{Binding MyProperty,
Converter={StaticResource InverseBoolRadioConverter}}" />
InverseBoolRadioConverter
,我可以忽略 Inverse 变量,并返回 true,因为我总是将其用作单选按钮的转换器。 - Maxoizspublic class BoolToOppositeBoolConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter,System.Globalization.CultureInfo culture) {
if (targetType != typeof(bool)) {
throw new InvalidOperationException("The target must be a boolean");
}
if (null == value) {
return null;
}
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter,System.Globalization.CultureInfo culture) {
if (targetType != typeof(bool)) {
throw new InvalidOperationException("The target must be a boolean");
}
if (null == value) {
return null;
}
return !(bool)value;
}
}
要使用它,请在资源部分声明。
<local:BoolToOppositeBoolConverter x:Key="BoolToOppositeBoolConverter_ValueConverter"/>
然后将其作为静态资源在绑定中使用:
<CheckBox IsChecked="{Binding YourProperty}" />
<CheckBox IsChecked="{Binding YourProperty,Converter={StaticResource BoolToOppositeBoolConverter_ValueConverter}}" />
请注意,该转换器只是一个简单的示例。如果您想在生产代码中使用它,请将其实现得更加优美。我没有测试过它,如果它不能正常工作,请留言。当使用MVVMLight
时,如果在XAML中设置了DataContext
:
DataContext="{Binding <Your ViewModel property name>, Source={StaticResource Locator}}"
BoolInverterConverter
会导致窗口第二次打开时出现Stack Overflow
错误。DataContext
,并在InitializeComponent()
后在窗口构造函数中使用代码进行操作。DataContext = ServiceLocator.Current.GetInstance<Your View Model class>();
经过一些测试,发现这还不够-在点击单选按钮时可能会随机弹出“堆栈溢出”错误。对我有效的解决方案是:不要使用转换器,而是使用组中其他单选按钮的另一个属性:
public bool Is9to1 { get; set; }
public bool Is1to9 { get { return !Is9to1; } set { Is9to1 = !value; } }
<RadioButton GroupName="Is9to1" IsChecked="{Binding Is1to9}"/>
<RadioButton GroupName="Is9to1" IsChecked="{Binding Is9to1}"/>
Mr-RandomQC
的答案来看,一切都正常。但是当我点击同一组中的另一个单选按钮时,相反的单选按钮会显示一个红色框。
我稍微修改了他的代码,将返回Binding.DoNothing
而不是像这样返回null
。
public class BoolRadioConverter : IValueConverter
{
public bool Inverse { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool boolValue = (bool)value;
return this.Inverse ? !boolValue : boolValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool boolValue = (bool)value;
if (!boolValue)
{
// Return Binding.DoNothing instead of Return null
return Binding.DoNothing;
}
return !this.Inverse;
}
}
如果您想使布尔值可为空(适用于无默认值/选中的单选按钮),这是对RandomEngy答案的小升级
public class BoolRadioConverter : IValueConverter
{
public bool Inverse { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool? boolValue = (bool?)value;
return this.Inverse ? !boolValue : boolValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool? boolValue = (bool?)value;
if (boolValue != null && (bool)!boolValue)
{
// We only care when the user clicks a radio button to select it.
return null;
}
return !this.Inverse;
}
}
其余部分与他的答案相同。
ragunathan的answer的简化版本。
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) =>
Convert(value);
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) =>
Convert(value);
private object Convert(object value) =>
value is bool ? !(bool)value : value;
回答晚了,但我们多年来一直这样做,首先是使用 WPF,现在是使用 WinUI 3
<StackPanel>
<TextBlock Text="Payment terms" />
<RadioButton
x:Name="rdo_on_account"
Content="Account"
GroupName="account"
IsChecked="{x:Bind ViewModel.IsOnAccount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<RadioButton
Content="Cash"
GroupName="account"
IsChecked="{Binding ElementName=rdo_on_account, Path=IsChecked, Converter={StaticResource BoolInvert}}" />
</StackPanel>
public class BoolInvert : IValueConverter
{
// convert the value to the destination format
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is bool)
{
if ((bool)value == true)
{
return false;
}
else
{
return true;
}
}
//not a bool
return value;
}
// convert from the destination format to the source format
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}