当颜色为十六进制时,控件背景的触发器不触发
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 相同,所以如果我把它放在最后,它会覆盖标准触发器。
假设我的 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 相同,所以如果我把它放在最后,它会覆盖标准触发器。