使用 OR 而不是 AND 的 MultiDataTrigger
MultiDataTrigger with OR instead of AND
我正在尝试在我的 Button
上设置多个 DataTriggers
。我做了一些研究,发现 MultiDataTrigger
允许你这样做。如果 CCTVPath == string.Empty
或 PermissionsFlag == false
,我希望 Button
的 Visibility
属性 设置为 false。这是我目前所拥有的;
<Button Grid.Column="3" x:Name="cctvFeedButton" Content="Live Feed"
Width="100" FontSize="16" HorizontalAlignment="Right" Margin="5" Click="OnCCTVButtonClick">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding CCTVPath}" Value=""/>
<Condition Binding="{Binding PermissionsFlag}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Hidden"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
在我的代码隐藏中,我这样设置 PermissionsFlag
;
public bool PermissionsFlag { get; set; }
private void OnPageLoaded(object sender, RoutedEventArgs e)
{
PermissionsFlag = false;
}
如您所见,PermissionsFlag
肯定是假的,CCTVPath
肯定是空的,但是 Button
永远不会被隐藏。我做错了什么?
更新:
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private bool _permissionsFlag;
public bool Flag
{
get { return _permissionsFlag; }
set
{
_permissionsFlag = value;
OnPropertyChanged("PermissionsFlag");
}
}
private void OnPageLoaded(object sender, RoutedEventArgs e)
{
Flag = false;
CCTVImageCollection = GetImages();
imageListBox.ItemsSource = CCTVImageCollection;
DataContext = this;
}
在我的 XAML:
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding PermissionsFlag}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
将条件转换为两个独立的数据触发器
<Style.Triggers>
<DataTrigger Binding="{Binding CCTVPath}" Value="">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding PermissionsFlag}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
确保绑定路径正确(检查 VS 输出 window 以获取可能的异常消息)
另外:不要只依赖 Button 的隐藏状态,在代码中正确实现权限 (OnCCTVButtonClick
)。在这里阅读原因:
How to Snoop proof your wpf application?
auto-属性 PermissionsFlag (public bool PermissionsFlag { get; set; }
) 不通知视图有关更改。
可以实现 INotifyPropertyChanged
接口(在我的测试中 window 是这样完成的:public partial class Window3 : Window, INotifyPropertyChanged
)然后在 属性 改变时引发事件。
这是我用于测试的完整工作示例
public partial class Window3 : Window, INotifyPropertyChanged
{
public Window3()
{
InitializeComponent();
this.DataContext = this;
//PermissionsFlag = true;
CCTVPath = "youtube.com";
}
private bool _permissionsFlag = false;
private string _cctvPath;
public bool PermissionsFlag
{
get { return _permissionsFlag; }
set
{
_permissionsFlag = value;
OnPropertyChanged("PermissionsFlag");
}
}
public string CCTVPath
{
get { return _cctvPath; }
set
{
_cctvPath = value;
OnPropertyChanged("CCTVPath");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
window xaml:
<Window x:Class="WpfDemos.Views.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" Height="300" Width="300">
<StackPanel>
<CheckBox Name="chkPermissionsFlag"
Content="PermissionsFlag"
IsChecked="{Binding Path=PermissionsFlag, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding Path=CCTVPath, UpdateSourceTrigger=PropertyChanged}"/>
<Button x:Name="cctvFeedButton" Content="Live Feed"
Width="100" FontSize="16" HorizontalAlignment="Right" Margin="5">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CCTVPath}" Value="">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=PermissionsFlag}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Window>
另一种解决方案是使用带有 MultiBinding 的单个 DataTrigger。您可以通过定义一个 'special-case' IMultiValueConverter 来使其工作,该转换器假定对象数组中有 2 个项目,如果第一项是空字符串或第二项为假,则 returns 为真。但是,您可能永远不会在代码中的其他任何地方使用该转换器。因此,如果您愿意预先做更多的工作,您可以定义 3 simple/reusable 个转换器。
1) 一个 [IMultiValueConverter] 'OrConverter,' 看起来像这样:
public class BooleanOrConverter : IMultiValueConverter {
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
return values.OfType<bool>().Any(b => b);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
2) [IValueConverter] 'IsNullOrEmpty' 字符串转换器:
public class StringIsNullOrEmptyConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return string.IsNullOrEmpty(value as string);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
3) 和一个 [IValueConverter] 'NotConverter:'
public class BooleanNotConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
然后,在您的 xaml 中,DataTrigger 将定义如下:
<Button x:Name="cctvFeedButton" Content="Live Feed"
Width="100" FontSize="16" HorizontalAlignment="Right" Margin="5">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource OrConverter}">
<Binding Path="PermissionFlag" Converter="{StaticResource NotConverter}"/>
<Binding Path="CCTVPath" Converter="{StaticResource IsNullOrEmptyConverter}"/>
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
为了可读性,我更喜欢这个解决方案而不是使用 2 个单独的 DataTriggers;它更好地表达了您正在定义的行为 - 它是 'or' 逻辑:一组应该隐藏按钮的 2 个条件。
我正在尝试在我的 Button
上设置多个 DataTriggers
。我做了一些研究,发现 MultiDataTrigger
允许你这样做。如果 CCTVPath == string.Empty
或 PermissionsFlag == false
,我希望 Button
的 Visibility
属性 设置为 false。这是我目前所拥有的;
<Button Grid.Column="3" x:Name="cctvFeedButton" Content="Live Feed"
Width="100" FontSize="16" HorizontalAlignment="Right" Margin="5" Click="OnCCTVButtonClick">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding CCTVPath}" Value=""/>
<Condition Binding="{Binding PermissionsFlag}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="Visibility" Value="Hidden"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
在我的代码隐藏中,我这样设置 PermissionsFlag
;
public bool PermissionsFlag { get; set; }
private void OnPageLoaded(object sender, RoutedEventArgs e)
{
PermissionsFlag = false;
}
如您所见,PermissionsFlag
肯定是假的,CCTVPath
肯定是空的,但是 Button
永远不会被隐藏。我做错了什么?
更新:
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private bool _permissionsFlag;
public bool Flag
{
get { return _permissionsFlag; }
set
{
_permissionsFlag = value;
OnPropertyChanged("PermissionsFlag");
}
}
private void OnPageLoaded(object sender, RoutedEventArgs e)
{
Flag = false;
CCTVImageCollection = GetImages();
imageListBox.ItemsSource = CCTVImageCollection;
DataContext = this;
}
在我的 XAML:
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding PermissionsFlag}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
将条件转换为两个独立的数据触发器
<Style.Triggers>
<DataTrigger Binding="{Binding CCTVPath}" Value="">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding PermissionsFlag}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
确保绑定路径正确(检查 VS 输出 window 以获取可能的异常消息)
另外:不要只依赖 Button 的隐藏状态,在代码中正确实现权限 (
OnCCTVButtonClick
)。在这里阅读原因:
How to Snoop proof your wpf application?
auto-属性 PermissionsFlag (public bool PermissionsFlag { get; set; }
) 不通知视图有关更改。
可以实现 INotifyPropertyChanged
接口(在我的测试中 window 是这样完成的:public partial class Window3 : Window, INotifyPropertyChanged
)然后在 属性 改变时引发事件。
这是我用于测试的完整工作示例
public partial class Window3 : Window, INotifyPropertyChanged
{
public Window3()
{
InitializeComponent();
this.DataContext = this;
//PermissionsFlag = true;
CCTVPath = "youtube.com";
}
private bool _permissionsFlag = false;
private string _cctvPath;
public bool PermissionsFlag
{
get { return _permissionsFlag; }
set
{
_permissionsFlag = value;
OnPropertyChanged("PermissionsFlag");
}
}
public string CCTVPath
{
get { return _cctvPath; }
set
{
_cctvPath = value;
OnPropertyChanged("CCTVPath");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
window xaml:
<Window x:Class="WpfDemos.Views.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" Height="300" Width="300">
<StackPanel>
<CheckBox Name="chkPermissionsFlag"
Content="PermissionsFlag"
IsChecked="{Binding Path=PermissionsFlag, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Text="{Binding Path=CCTVPath, UpdateSourceTrigger=PropertyChanged}"/>
<Button x:Name="cctvFeedButton" Content="Live Feed"
Width="100" FontSize="16" HorizontalAlignment="Right" Margin="5">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CCTVPath}" Value="">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=PermissionsFlag}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Window>
另一种解决方案是使用带有 MultiBinding 的单个 DataTrigger。您可以通过定义一个 'special-case' IMultiValueConverter 来使其工作,该转换器假定对象数组中有 2 个项目,如果第一项是空字符串或第二项为假,则 returns 为真。但是,您可能永远不会在代码中的其他任何地方使用该转换器。因此,如果您愿意预先做更多的工作,您可以定义 3 simple/reusable 个转换器。
1) 一个 [IMultiValueConverter] 'OrConverter,' 看起来像这样:
public class BooleanOrConverter : IMultiValueConverter {
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
return values.OfType<bool>().Any(b => b);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
2) [IValueConverter] 'IsNullOrEmpty' 字符串转换器:
public class StringIsNullOrEmptyConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return string.IsNullOrEmpty(value as string);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
3) 和一个 [IValueConverter] 'NotConverter:'
public class BooleanNotConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
然后,在您的 xaml 中,DataTrigger 将定义如下:
<Button x:Name="cctvFeedButton" Content="Live Feed"
Width="100" FontSize="16" HorizontalAlignment="Right" Margin="5">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource OrConverter}">
<Binding Path="PermissionFlag" Converter="{StaticResource NotConverter}"/>
<Binding Path="CCTVPath" Converter="{StaticResource IsNullOrEmptyConverter}"/>
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
为了可读性,我更喜欢这个解决方案而不是使用 2 个单独的 DataTriggers;它更好地表达了您正在定义的行为 - 它是 'or' 逻辑:一组应该隐藏按钮的 2 个条件。