WPF绑定枚举到可见性

Ami*_*sky 3 c# wpf xaml binding

我正在使用MVVM模式(入门)用于WPF应用程序

我有一个在模型TrainDirectionTrain.cs中定义的属性:

public enum TrainDirection
{
    Unknown,
    None,
    Left,
    Right
}
Run Code Online (Sandbox Code Playgroud)

在视图中我想显示/隐藏一个symbol表示trainObject根据枚举值的值.

在此输入图像描述

我创建了一个'UserControl':

<Grid >
    <Path x:Name="TrainToRight" Data="M80,160L220,160 270,190 220,220 80,220"  Stretch="Fill"  StrokeThickness="2" Opacity="0.9"      
    </Path>

    <Path x:Name="TrainToLeft" Data="M130,160L260,160 260,220 130,220 80,190z" Stretch="Fill"  StrokeThickness="2" Opacity="0.9"
    </Path>        
</Grid>
Run Code Online (Sandbox Code Playgroud)

我想我需要类似a的东西trainDirectionToVisibilityConverter来将可见性Property绑定到TrainDirection,以便根据Direction显示/隐藏正确的符号.

我想用这种方式实现转换器:

class TrainDirectionToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var direction = (TrainDirection)value;
        switch (direction)
        {
            case TrainDirection.Unknown:
                return Application.Current.FindResource("TrainDirectionUnknown");

            case TrainDirection.None:
                return Application.Current.FindResource("TrainDirectionNone");

            case TrainDirection.Left:
                return Application.Current.FindResource("TrainDirectionLeft");

            case TrainDirection.Right:
                return Application.Current.FindResource("TrainDirectionRight");

            default: throw new ArgumentException($"Unsupported TranDirection value: {direction}");
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

还有一个ResourceDictionary,其中为App定义了自定义样式.

我该如何实现这种绑定?

一些解释将非常有用,因为我刚刚开始使用c#和WPF编程

Mar*_*man 8

不需要转换器,你可以只使用数据触发器,如下所示:

    <Path x:Name="TrainToRight" Data="M80,160L220,160 270,190 220,220 80,220"  Stretch="Fill"  StrokeThickness="2" Opacity="0.9">
        <Path.Style>
            <Style TargetType="{x:Type Path}">
                <Setter Property="Visibility" Value="Hidden" /> <!-- default value -->
                <Style.Triggers>
                    <DataTrigger Binding="{Binding TrainDirectionProperty}" Value="Unknown">
                        <Setter Property="Visibility" Value="Visible" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Path.Style>
    </Path>
Run Code Online (Sandbox Code Playgroud)

每个路径必须执行一次.

或者,您也可以声明单个路径并使用DataTriggers将"Data"属性设置为您之后的路径数据:

<Path Stretch="Fill" StrokeThickness="2" Stroke="Black" Opacity="0.9">
    <Path.Style>
        <Style TargetType="{x:Type Path}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding TrainDirectionProperty}" Value="Left">
                    <Setter Property="Data" Value="M130,160L260,160 260,220 130,220 80,190z" />
                </DataTrigger>
                <DataTrigger Binding="{Binding TrainDirectionProperty}" Value="Right">
                    <Setter Property="Data" Value="M80,160L220,160 270,190 220,220 80,220" />
                </DataTrigger>
                <!-- etc -->
            </Style.Triggers>
        </Style>
    </Path.Style>
</Path>
Run Code Online (Sandbox Code Playgroud)

另一种可能性是创建一个所有路径都使用的通用样式.在这种情况下,您需要一些其他方法来区分它们,一种方法是将它们的值存储在"Tag"属性中,您可以将其用于任意自定义数据:

<Path Tag="{x:Static vm:TrainDirection.Right}" Data="M80,160L220,160 270,190 220,220 80,220" Style="{StaticResource TrainDirectionStyle}" />
<Path Tag="{x:Static vm:TrainDirection.Left}" Data="M130,160L260,160 260,220 130,220 80,190z" Style="{StaticResource TrainDirectionStyle}" />
... etc...
Run Code Online (Sandbox Code Playgroud)

然后创建一个样式,将绑定值与标记中的值进行比较,并相应地设置可见性:

<Style x:Key="TrainDirectionStyle" TargetType="{x:Type Path}">
    <Setter Property="Stretch" Value="Fill" />
    <Setter Property="StrokeThickness" Value="2" />
    <Setter Property="Stroke" Value="Black" />
    <Setter Property="Opacity" Value="0.9" />
    <Setter Property="Visibility" Value="Hidden" />
    <Style.Triggers>
        <DataTrigger Value="True">
            <DataTrigger.Binding>
                <MultiBinding Converter="{StaticResource EqualityConverter}">
                    <Binding Path="TrainDirectionProperty" />
                    <Binding RelativeSource="{RelativeSource Self}" Path="Tag" />
                </MultiBinding>
            </DataTrigger.Binding>
            <Setter Property="Visibility" Value="Visible" />
        </DataTrigger>
    </Style.Triggers>
</Style>
Run Code Online (Sandbox Code Playgroud)

这是保证转换器的罕见情况之一,但它是一个通用的相等比较器,可以在代码的其他部分使用,而不是仅仅专门支持这种情况:

public class EqualityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return object.Equals(values[0], values[1]);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的首选选项可能是#2,因为它最小化了绑定和GUI对象的数量,同时仍然相对容易阅读和理解.