为Brush创建一个WPF ValueConverter

3
今天在Nerd Plus Art博客上,有一篇关于创建WPF箭头资源的文章,作者经常使用这些资源。我有一个副业项目需要前进和后退按钮,所以我认为左右箭头在这些按钮上非常适合。
我将LeftArrowRightArrow几何图形添加到应用程序资源中,然后将它们用作按钮的内容:
<Application x:Class="Notes.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Views/MainWindow.xaml">
    <Application.Resources>
        <Geometry x:Key="RightArrow">M0,0 L1,0.5 0,1Z</Geometry>
        <Geometry x:Key="LeftArrow">M0,0.5 L1,1 1,0Z</Geometry>
    </Application.Resources>
</Application>

<Button x:Name="BackButton"
    Padding="5,5,5,5"
    Command="{x:Static n:Commands.GoBackCommand}">
    <Path Data="{StaticResource LeftArrow}" Width="10" Height="8"
        Stretch="Fill" Fill="Black"/>
    </Button>
<Button x:Name="ForwardButton"
    Padding="5,5,5,5"
    Command="{x:Static n:Commands.GoForwardCommand}">
    <Path Data="{StaticResource RightArrow}" Width="10" Height="8"
        Stretch="Fill" Fill="Red" />
</Button>

那个方法可行,但不管按钮是否启用箭头都是黑色的。因此,我创建了一个ValueConverter,将bool类型转换为Brush类型:
class EnabledColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        bool b = (bool)value;
        return b ? Brushes.Black : Brushes.Gray;
    }

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

(我意识到应该使用系统颜色而不是硬编码的黑色和灰色,但我只是想先让它工作。)

我修改了PathFill属性,使用我的转换器(我在应用程序资源中创建):

<Path Data="{StaticResource LeftArrow}" Width="10" Height="8"
    Stretch="Fill"
    Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=IsEnabled, Converter={StaticResource EnabledColorConverter}}"/>

很不幸,这并没有起作用,我不确定原因。当我运行它时,箭头根本没有被绘制。我在Visual Studio的输出窗口中检查了一下,没有显示任何绑定错误。我还验证了转换器中的bool值是否正确,基于按钮是否应该启用。
如果我将Path改回TextBlock(并以与Path.Fill相同的方式绑定其Foreground属性),则文本始终以黑色绘制。
我做错了什么吗?为什么我的转换器返回的Brush没有用于渲染按钮中的Path

不确定为什么您的代码无法工作,但我会使用样式触发器来完成这个任务... - user1228
3个回答

3

针对这种UI状态更新,建议使用触发器(triggers)来实现,这样可以避免编写值转换器(value converter),而且代码量更短。

尝试一下这个:

<Application x:Class="Notes.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Views/MainWindow.xaml">
    <Application.Resources>
        <Geometry x:Key="RightArrow">M0,0 L1,0.5 0,1Z</Geometry>
        <Geometry x:Key="LeftArrow">M0,0.5 L1,1 1,0Z</Geometry>

         <!-- Base Arrow Style, with a trigger to toggle it Gray when its parent button is disabled -->
        <Style x:Key="ArrowStyle" TargetType="Path">
            <Setter Property="Width" Value="10"/>
            <Setter Property="Height" Value="8"/>
            <Setter Property="Stretch" Value="Fill"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=IsEnabled}" Value="False">
                    <Setter Property="Fill" Value="Gray"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>

        <!-- Left Arrow Style, with the Left Arrow fill and data -->
        <Style x:Key="LeftArrowStyle" BasedOn="{StaticResource ArrowStyle}" TargetType="Path">
            <Setter Property="Fill" Value="Black"/>
            <Setter Property="Data" Value="{StaticResource LeftArrow}"/>
        </Style>

        <!-- Right Arrow Style, with the Right Arrow fill and data -->
        <Style x:Key="RightArrowStyle" BasedOn="{StaticResource ArrowStyle}" TargetType="Path">
            <Setter Property="Fill" Value="Red"/>
            <Setter Property="Data" Value="{StaticResource RightArrow}"/>
        </Style>
    </Application.Resources>

    <Button x:Name="BackButton" Padding="5,5,5,5" IsEnabled="False">
        <Path Style="{StaticResource LeftArrowStyle}"/>
    </Button>
    <Button x:Name="ForwardButton" Padding="5,5,5,5">
        <Path Style="{StaticResource RightArrowStyle}"/>
    </Button>
</Application>

然后,您可以设置默认的 LeftArrowStyle 和 RightArrowStyle,分别用于左箭头和右箭头。如果您将其设置在路径本身上,则该值将优先于样式或其触发器所做的任何事情并覆盖它们。基本样式 ArrowStyle 包含一个绑定到父按钮的 DataTrigger - 当 IsEnabled 为 false 时触发,并将 Path 的 Fill 更改为 Gray。


我想我会采用ppx的方法,直接绑定到按钮的前景似乎是更好的方法。不过,非常感谢您提供的信息丰富的答案。 :) - Andy

2
为什么不将路径的填充绑定到按钮的前景色呢?
<Button x:Name="BackButton"
    Padding="5,5,5,5"
    Command="{x:Static n:Commands.GoBackCommand}">
    <Path Data="{StaticResource LeftArrow}" Width="10" Height="8"
        Stretch="Fill" Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=Foreground"/>
    </Button>

那将是一种更直接的方法,它能够工作。感谢帮助。 :) - Andy

0

你的代码基本上是有效的。我认为你的静态资源可能有误,因为你没有指定从哪里获取转换器。

你可能需要:

<Window.Resources>
    <conv:EnabledColorConverter x:Key="brushConv" />
</Window.Resources>

然后指定你的绑定方式为:

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=IsEnabled, Converter={StaticResource brushConv}}

我已经在Application.Resources中定义了转换器 - 我只是没有在上面的代码中包含它。对于造成的困惑,我感到抱歉。 - Andy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接