我有一个描述 GUI 部分的 WPF xaml 文件,我希望特定控件的启用/禁用依赖于其他两个控件。目前代码看起来像这样:
<ComboBox Name="MyComboBox"
IsEnabled="{Binding ElementName=SomeCheckBox, Path=IsChecked}"/>
但我希望它也依赖于另一个复选框,例如:
<ComboBox Name="MyComboBox"
IsEnabled="{Binding ElementName=SomeCheckBox&AnotherCheckbox, Path=IsChecked}"/>
最好的方法是什么?我不禁觉得我错过了一些明显的东西或者以错误的方式处理这个问题?
MultiBinding
与实现 IMultiValueConverter
的转换器一起使用。
只是为了给出答案,您可以(几乎)复制和粘贴:
需要静态资源:
<converterNamespace:BooleanAndConverter x:Key="booleanAndConverter" />
组合框:
<ComboBox Name="MyComboBox">
<ComboBox.IsEnabled>
<MultiBinding Converter="{StaticResource booleanAndConverter}">
<Binding ElementName="SomeCheckBox" Path="IsChecked" />
<Binding ElementName="AnotherCheckbox" Path="IsChecked" />
</MultiBinding>
</ComboBox.IsEnabled>
</ComboBox>
转换器的代码:
namespace ConverterNamespace
{
public class BooleanAndConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
foreach (object value in values)
{
if ((value is bool) && (bool)value == false)
{
return false;
}
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("BooleanAndConverter is a OneWay converter.");
}
}
}
您也可以尝试相同的较短版本:
public class BooleanAndConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return values.OfType<IConvertible>().All(System.Convert.ToBoolean);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
public class BooleanOrConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return values.OfType<IConvertible>().Any(System.Convert.ToBoolean);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
当然,您可能还需要转换器来提高可见性:
public class BooleanOrToVisibilityConverter : IMultiValueConverter
{
public Visibility HiddenVisibility { get; set; }
public bool IsInverted { get; set; }
public BooleanOrToVisibilityConverter()
{
HiddenVisibility = Visibility.Collapsed;
IsInverted = false;
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool flag = values.OfType<IConvertible>().Any(System.Convert.ToBoolean);
if (IsInverted) flag = !flag;
return flag ? Visibility.Visible : HiddenVisibility;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class BooleanAndToVisibilityConverter : IMultiValueConverter
{
public Visibility HiddenVisibility { get; set; }
public bool IsInverted { get; set; }
public BooleanAndToVisibilityConverter()
{
HiddenVisibility = Visibility.Collapsed;
IsInverted = false;
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool flag = values.OfType<IConvertible>().All(System.Convert.ToBoolean);
if (IsInverted) flag = !flag;
return flag ? Visibility.Visible : HiddenVisibility;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
我相信您可能必须将 MultiBinding 与 MultiValueConverter 一起使用。请参阅此处:http://www.developingfor.net/wpf/multibinding-in-wpf.html
这是一个直接相关的示例:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5b9cd042-cacb-4aaa-9e17-2d615c44ee22
作为 qqbenq 答案的延伸:
添加了处理集合的
Count
的功能,例如,如果您想检查 ListView
的某些项目是否被选中。
转换器:
public class IsEnabledConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
foreach (var value in values)
{
switch (value)
{
case bool b when !b:
case int i when i == 0:
return false;
}
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return null;
}
}
命名空间
<theNamespace:IsEnabledConverter x:Key="IsEnabledConverter"/>
按钮
<Button x:Name="MyButton">
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource IsEnabledConverter}">
<Binding ElementName="MyListView" Path="SelectedItems.Count"/>
<Binding ElementName="MyCheckBox" Path="IsChecked"/>
</MultiBinding>
</Button.IsEnabled>
</Button>
当你不想使用MultiBinding时
public class AndEnabledTextBox : TextBox
{
public static readonly DependencyProperty AndEnabled1SubProperty =
DependencyProperty.Register(nameof(AndEnabled1), typeof(bool), typeof(AndEnabledTextBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnAndEnabledPropertyChanged)));
public static readonly DependencyProperty AndEnabled2SubProperty =
DependencyProperty.Register(nameof(AndEnabled2), typeof(bool), typeof(AndEnabledTextBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnAndEnabledPropertyChanged)));
public bool AndEnabled1 { get { return (bool)GetValue(AndEnabled1SubProperty); } set { SetValue(AndEnabled1SubProperty, value); } }
public bool AndEnabled2 { get { return (bool)GetValue(AndEnabled2SubProperty); } set { SetValue(AndEnabled2SubProperty, value); } }
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
IsEnabled = AndEnabled1 && AndEnabled2;
}
protected static void OnAndEnabledPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
AndEnabledTextBox textBox = (AndEnabledTextBox)obj;
textBox.IsEnabled = textBox.AndEnabled1 && textBox.AndEnabled2;
}
}
XAML代码(当您使用继承的控件时会更加简化)。
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1">
<StackPanel>
<ToggleButton x:Name="switch1" Content="{Binding ElementName=switch1, Path=IsChecked}"/>
<ToggleButton x:Name="switch2" Content="{Binding ElementName=switch2, Path=IsChecked}"/>
<local:AndEnabledTextBox Text="TEXT"
AndEnabled1="{Binding ElementName=switch1, Path=IsChecked, Mode=OneWay}"
AndEnabled2="{Binding ElementName=switch2, Path=IsChecked, Mode=OneWay}"/>
</StackPanel>
</Window>