当颜色为十六进制时,控件背景的触发器不触发

Trigger for control background not firing when color is in hexadecimal

假设我的 window 中有 3 个按钮:

<Button Content="Green Button" Background="LimeGreen" Style="{StaticResource ButtonStyle}" Margin="0,0,0,10" />
<Button Content="Red Button" Background="Red" Style="{StaticResource ButtonStyle}" Margin="0,0,0,10" />
<Button Content="Hex Button" Background="#FF32CD32" Style="{StaticResource ButtonStyle}" />

在 app.xaml 中,我创建了一个将被所有按钮使用的样式:

<Application.Resources>

    <Style x:Key="ButtonStyle" TargetType="{x:Type ButtonBase}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ButtonBase}">
                    <Border Name="border"
                        BorderThickness="1.5"
                        Padding="{TemplateBinding Padding}"
                        BorderBrush="Black"
                        Background="{TemplateBinding Background}">
                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="border" Property="Opacity" Value="0.9" />
                        </Trigger>

                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsPressed" Value="True" />
                                <Condition Property="Background" Value="Red" />
                            </MultiTrigger.Conditions>

                            <Setter TargetName="border" Property="Background" Value="DarkOrange" />
                        </MultiTrigger>

                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsPressed" Value="True" />
                                <Condition Property="Background" Value="LimeGreen" />
                            </MultiTrigger.Conditions>

                            <Setter TargetName="border" Property="Background" Value="Chartreuse" />
                        </MultiTrigger>
                    </ControlTemplate.Triggers>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</Application.Resources>

对于前两个按钮,一切正常。但是,当我尝试单击第三个按钮时,没有任何反应。 即使我添加另一个条件为 "Background value="#FF32CD32" 的多重触发器(应该与 LimeGreen 相同),它也没有任何改变。

十六进制值是否适用于触发器?

好吧,在获得更多 WPF 经验后,我决定再试一次。答案几乎立刻就来了...

问题是,条件中提供的值被读取为颜色。 XAML 单独无法解析它们的 RGB 表示。让我们看一个例子:

如果背景颜色为红色(已在 Colors/Brushes 枚举中定义),则可以正确读取值。但是,如果提供的值是#FFABCDEF,它也是一种颜色,但未定义为标准颜色。对于 XAML 它只是一个普通字符串。因此,通过提供十六进制值而不是预定义的枚举,触发器将失败。

此问题的解决方案是创建自定义转换器。它将颜色值转换为其相应的字符串表示形式。然后,当我们检查条件中的值时,转换器将为我们提供有效的字符串。

解决方案:

首先我创建了转换器,returns 颜色的有效十六进制值:

public class ColorToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Color c = (value as SolidColorBrush).Color;

        return c.ToString();
    }

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

然后,在您的样式文件中,包含创建的转换器的命名空间:

xmlns:conv="clr-namespace:ButtonTest.Converters"

在样式文件资源中(在本例中,它只是 App.xaml):

<conv:ColorToStringConverter x:Key="ColorToStringConverter" />

最后,触发器:

<Trigger Property="IsMouseOver" Value="True">
    <Setter TargetName="border" Property="Opacity" Value="0.9" />
</Trigger>

<!-- Custom colors handling there -->
<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsPressed}" Value="True" />
        <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=Background, Converter={StaticResource ColorToStringConverter}}" Value="#FF32CD32" />
    </MultiDataTrigger.Conditions>

    <Setter TargetName="border" Property="Background" Value="Chartreuse" />
</MultiDataTrigger>

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="IsPressed" Value="True" />
        <Condition Property="Background" Value="Red" />
    </MultiTrigger.Conditions>

    <Setter TargetName="border" Property="Background" Value="DarkOrange" />
</MultiTrigger>

<MultiTrigger>
    <MultiTrigger.Conditions>
        <Condition Property="IsPressed" Value="True" />
        <Condition Property="Background" Value="LimeGreen" />
    </MultiTrigger.Conditions>

    <Setter TargetName="border" Property="Background" Value="Chartreuse" />
</MultiTrigger>

注意触发器的优先级:十六进制触发器应该在标准颜色之前声明。在我的示例中,#FF32CD32 与 LimeGreen 相同,所以如果我把它放在最后,它会覆盖标准触发器。