为画笔创建 WPF ValueConverter

发布于 2024-07-23 08:08:04 字数 2594 浏览 1 评论 0原文

关于 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

On the Nerd Plus Art blog today, there was a post about creating WPF Resources for arrows, which the author uses frequently. I have a side project that has Back and Forward buttons, so I thought that the Left and Right arrows would work great on those buttons.

I added the LeftArrow and RightArrow Geometries to my application's resources, and then used them as the content of the buttons:

<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>

That worked, except that the arrows were drawn in black regardless of whether the button was enabled or not. So, I created a ValueConverter to go from a bool to a 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();
    }
}

(I realize that I should probably use system colors instead of hard coded black and gray, but I just wanted to get this working, first.)

I modified the Fill property of the Path to use my converter (which I created within the application's resources):

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

Unfortunately, this doesn't work, and I'm not sure why. When I run it, the arrow isn't drawn at all. I checked the Output window in Visual Studio, and no binding errors were displayed. I also verified that the bool is the right value in the converter, based on the whether the button should be enabled or not.

If I change the Path back to a TextBlock (and bind its Foreground property in the same manner as Path.Fill), the text is always drawn in black.

Am I doing something wrong? Why is the Brush returned by my converter not used to render the Path in the button?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

请恋爱 2024-07-30 08:08:04

对于这种 UI 状态更新,请尝试使用触发器; 它可以让你免去编写值转换器的麻烦,而且编写起来要短得多。

尝试以下操作:

<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,它就会触发,并将路径的填充更改为灰色。

For this kind of UI state updates, try using triggers instead; it'll save you from writing a value converter, and it's a lot shorter to write.

Try this:

<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>

Then, you set your default fill in LeftArrowStyle and RightArrowStyle, for the left and right arrows, respectively. If you set it on the Path itself, then that value would take precedence and override anything a style or its trigger may do. The base style, ArrowStyle, contains a DataTrigger bound to the parent button - it fires whenever IsEnabled is false, and changes the Path's Fill to Gray.

维持三分热 2024-07-30 08:08:04

为什么不将路径的填充绑定到按钮的前景呢?

<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>

Why no just bind the Fill of your Path to the Foreground of the Button?

<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>
北音执念 2024-07-30 08:08:04

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

您可能需要

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

然后将您的绑定指定为:

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

Your code essentially works. I think your static resource may be wrong as your not specifying where this is getting the converter from.

You probably need

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

and then specify your binding as:

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=IsEnabled, Converter={StaticResource brushConv}}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文