【问题标题】:Multiple values single data trigger WPF多值单数据触发WPF
【发布时间】:2019-04-08 14:41:09
【问题描述】:

我有以下代码。

                <Button.Style>
                    <Style BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"
                           TargetType="{x:Type Button}">
                        <Setter Property="Visibility" Value="Collapsed" />
                        <Style.Triggers>

                            <DataTrigger Binding="{Binding Status, Mode=OneWay}"
                                         Value="{x:Static comm:DeviceStatus.Standby}">
                                <Setter Property="Visibility" Value="Visible" />
                            </DataTrigger>

                            <DataTrigger Binding="{Binding Status, Mode=OneWay}"
                                         Value="{x:Static comm:DeviceStatus.Busy}">
                                <Setter Property="Visibility" Value="Visible" />
                            </DataTrigger>

                            <DataTrigger Binding="{Binding Status, Mode=OneWay}"
                                         Value="{x:Static comm:DeviceStatus.Offline}">
                                <Setter Property="Visibility" Value="Visible" />
                            </DataTrigger>

                            <DataTrigger Binding="{Binding Status, Mode=OneWay}"
                                         Value="{x:Static comm:DeviceStatus.StartingStream}">
                                <Setter Property="Visibility" Value="Visible" />
                            </DataTrigger>

                            <DataTrigger Binding="{Binding Status, Mode=OneWay}"
                                         Value="{x:Static comm:DeviceStatus.Connecting}">
                                <Setter Property="Visibility" Value="Visible" />
                            </DataTrigger>

                            <DataTrigger Binding="{Binding Status, Mode=OneWay}"
                                         Value="{x:Static comm:DeviceStatus.Disconnecting}">
                                <Setter Property="Visibility" Value="Visible" />
                            </DataTrigger>

                            <DataTrigger Binding="{Binding Status, Mode=OneWay}"
                                         Value="{x:Static comm:DeviceStatus.DownloadingFiles}">
                                <Setter Property="Visibility" Value="Visible" />
                            </DataTrigger>

                        </Style.Triggers>
                    </Style>
                </Button.Style>

该按钮默认是隐藏的,当视图模型中的属性具有几个值之一时可见。该属性是一个名为 DeviceStatus 的枚举类型。

基本上,它对提供的触发器执行 OR 操作。 因此,按钮的可见性取决于: Status == StandBy ||状态 == 忙 || ...

如何在不必有 8 个触发器的情况下实现这一点?

我想要以下内容:

<DataTrigger Binding="{Binding Status, Mode=OneWay}">
    <DataTrigger.AnyValue>
        <AnyValueItem Value="{x:Static comm:DeviceStatus.Standby}" />
        <AnyValueItem Value="{x:Static comm:DeviceStatus.Busy}" />
        <AnyValueItem Value="{x:Static comm:DeviceStatus.Offline}" />
        ...
    </DataTrigger.AnyValue>
    <Setter Property="Visibility" Value="Visible" />
</DataTrigger>

如果绑定获得任何提供的值,则按钮的可见性设置为可见。 谢谢!

【问题讨论】:

  • 使用转换器。
  • @l33t 我一直在想这也许是可能的。请您提供更详细的解释。

标签: c# .net wpf windows


【解决方案1】:

DataTrigger 不支持某种可能值列表。它只有一个 Value 属性。

解决此问题的最简单方法是向视图模型添加一个属性,该属性返回一个值,指示是否显示Button

public bool IsVisible => Status == Standby || Status == Busy || ...;

XAML:

<DataTrigger Binding="{Binding IsVisible, Mode=OneWay}" Value="True">
    <Setter Property="Visibility" Value="Visible" />
</DataTrigger>

另一个选项可能是使用@l33t 建议的converter。然后,您只需将逻辑移出视图模型,例如:

public class Converter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        ViewModel vm = value as ViewModel;
        return (vm != null && (vm.Status == Standby || vm.Status == Busy || ...)) ? Vsibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML:

<Style ...>
    <Style.Resources>
        <local:Converter x:Key="conv" />
    </Style>
    <Setter Property="Visibility" Value="{Binding Path=., Converter={StaticResource converter}}" />

【讨论】:

  • 基本上,如果有办法通过 XAML 将参数数组发送到转换器,我想我会采用转换器的解决方案。否则,对于枚举值的每种组合,我都需要一个转换器。有没有办法让您的解决方案更通用?
【解决方案2】:

你可以创建一个属性:

private DeviceStatus _Status;
    public DeviceStatus Status
    {
        get { return _Status; }
        set
        {
            this.Set(ref _Status, value);
            RaisePropertyChanged(nameof(this.StatusVisibility));
        }
    }

    public Visibility StatusVisibility
    {
        get
        {
            switch (_Status)
            {
                case DeviceStatus.Busy: //add other statuses here
                    return Visibility.Visible;
            }

            return Visibility.Collapsed;
        }
    }

然后在您的按钮中:

<Button Content="MyButton" Visibility="{Binding StatusVisibility}"></Button>

【讨论】:

    【解决方案3】:

    阅读答案后,我得到了一些想法,并找到了一个令人满意的可扩展解决方案。

    首先我创建了以下转换器。

    public sealed class EnumOrConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
    
            DeviceStatus status = (DeviceStatus)value;
    
            DeviceStatus[] statuses = parameter as DeviceStatus[];
    
            if (statuses.Any(s => s == status))
            {
                return Visibility.Visible;
            }
            else
            {
                return Visibility.Collapsed;
            }
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    其次,我只是将以下代码添加到 XAML。

    <Button Command="{Binding SomeCommand}">
        <Button.Style>
            <Style BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"
                               TargetType="{x:Type Button}">
                <Setter Property="Visibility">
                    <Setter.Value>
                        <Binding Path="Status" Converter="{StaticResource EnumOrConverter}">
                            <Binding.ConverterParameter>
                                <x:Array Type="{x:Type comm:DeviceStatus}">
                                    <x:Static Member="comm:DeviceStatus.Standby" />
                                    <x:Static Member="comm:DeviceStatus.Busy" />
                                    <x:Static Member="comm:DeviceStatus.Offline" />
                                    <x:Static Member="comm:DeviceStatus.StartingStream" />
                                    <x:Static Member="comm:DeviceStatus.Connecting" />
                                    <x:Static Member="comm:DeviceStatus.Disconnecting" />
                                    <x:Static Member="comm:DeviceStatus.DownloadingFiles" />
                                </x:Array>
                            </Binding.ConverterParameter>
                        </Binding>
                    </Setter.Value>
                </Setter>
            </Style>
        </Button.Style>
    </Button>
    

    这允许我为许多其他按钮重用转换器逻辑,而无需向 ViewModel 添加变量或属性。同样发生的事情是转换器封装了“OR:ing”参数和“默认为 Visibility.Collapsed”的逻辑。添加一个新参数只需要 XAML 中的一行代码,这就是它所属的位置。

    【讨论】:

      猜你喜欢
      • 2016-03-12
      • 2011-07-25
      • 2015-07-31
      • 2021-12-20
      • 2014-10-09
      • 2018-02-02
      • 1970-01-01
      • 2023-03-19
      • 2013-09-05
      相关资源
      最近更新 更多