问题描述
||
我有一个WPF应用程序,该应用程序附带了由项目类型定义的Label,TextBox等默认样式集(未定义显式键)。
在该应用程序中,使用了两个主要容器,一个使用深色背景,另一个使用浅色背景,因此有时使用黑色作为Label的前景色是正确的,有时则是非常错误的。另一方面,编辑器总是在传统上使用浅色背景和深色前景进行样式设置,因此我不能仅将所有子元素的前景设置为相反的。
有没有一种优雅的方法可以使我的标签(可能还有TextBlocks)决定依赖于“其”背景的前景色?我只想在两种颜色之间切换,因此不需要自动对比度最大化,只需要一个阈值就可以避免白色底色上的白色字体。
我也不想定义两组默认样式,因此我强烈寻求某种方式使我的单个Label-Default-Style适用于两种背景变体。
是否可以(并且在不影响性能的前提下)向样式添加触发器/绑定,以评估当前的背景色?
另外,我将对最佳做法感兴趣,如何在不遇到上述问题的情况下,为某些FrameworkElement(尤其是容器/面板)设置干净的背景色。
这是我尝试过的(当然是简化的):
<UniformGrid>
<UniformGrid.Resources>
<!-- SimpleStyles: Label -->
<Style x:Key=\"{x:Type Label}\" targettype=\"{x:Type Label}\">
<Setter Property=\"HorizontalContentAlignment\" Value=\"Left\"/>
<Setter Property=\"VerticalContentAlignment\" Value=\"Top\"/>
<Setter Property=\"Template\">
<Setter.Value>
<ControlTemplate targettype=\"{x:Type Label}\">
<Border>
<ContentPresenter HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\" VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\" RecognizesAccessKey=\"True\"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property=\"Background\" Value=\"Black\">
<Setter Property=\"Foreground\" Value=\"Red\"/>
</Trigger>
<Trigger Property=\"IsEnabled\" Value=\"false\">
<Setter Property=\"Foreground\" Value=\"#888888\"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UniformGrid.Resources>
<Label x:Name=\"bgSetExplicitly\" Background=\"Black\">abc
</Label>
<Border Background=\"Black\">
<Label x:Name=\"bgInheritedFromParent\" >abc
</Label>
</Border>
<Label>abc
</Label>
<Label>abc
</Label>
如果Label具有明确的背景设置(x:Name = bgSetExplicitly),但是如果背景是VisualTree中父级的“继承”,则可以看到标签的背景被很好地选择了。 = \“ bgInheritedFromParent \”),不是。
我很乐意让样式能够评估“有效背景”(无论它来自何处)并为此背景选择适当的前景画笔。
解决方法
这个问题似乎暗示着一个更深层次的问题。我猜您尚未合并前景色的管理,因此您有一个应用程序,该应用程序具有在各处设置前景色的代码或样式。现在,您正在处理其中的一种含义。
我将面对更深层次的问题并解决该问题。我不太了解为什么您不赞成创建默认样式,但是暂时假设您有充分的理由不这样做(“ \”我应该在某个时候创建默认样式,但现在我还没有,而且我的应用程序变大了,这太难了,”(在这种情况下,我有不同的建议)如何创建全局资源?
在应用程序的资源字典中为控件的前景色和背景色创建对象,并修复XAML,以便它使用directly1ѭ标记扩展名从资源字典中获取它们,而不是直接引用画笔。在代码中,不要将控件上的
Foreground
属性直接设置为画笔,而是使用GetResource
获取画笔。并以相同方式设置背景。
完成此操作后,如果要在应用程序中全局更改前景色/背景色,则只需更改资源。
基本上,这就是开始使WPF应用程序可换肤的方式,这似乎是您要走的路。
, 最简单的方法是将TextBoxes等的前景色绑定到其包含元素的背景,然后使用值转换器进行更改。如果您仅使用两种颜色,则这特别容易。
举个例子....
public class ColorSwapper : IValueConverter
{
public object Convert(object value,Type targetType,object parameter,System.Globalization.CultureInfo culture)
{
if (value == null) { return DependencyProperty.UnsetValue; }
Color srcColor = (value as SolidColorBrush).Color;
if (srcColor == Colors.Black)
{
return new SolidColorBrush(Colors.White);
}
else
{
return new SolidColorBrush(Colors.Black);
}
}
...
还有一些示例XAML ...
<Grid Grid.Column=\"1\" Name=\"RightGrid\" Background=\"White\">
<TextBlock Text=\"Hello Nurse!\" Foreground=\"{Binding ElementName=RightGrid,Path=Background,Converter={StaticResource ColorSwapper}}\"/>
</Grid>
当然,您可能会希望根据自己的特定需求进行一些调整和清理,但这可以做到。
, 这是另一种可能的方法。如果您的应用程序仅具有所有深色/浅色背景及其修饰,则可以使用我在其他答案中提到的\'ColorSwapper \',尝试使用这种方法。
<Window>
<Window.Resources>
<local:ColorSwapper x:Key=\"swapper\"/>
<SolidColorBrush x:Key=\"BackBrush\" Color=\"Black\"/>
<!--<SolidColorBrush x:Key=\"BackBrush\" Color=\"White\"/>-->
<Style TargetType=\"{x:Type TextBlock}\">
<Setter Property=\"Foreground\" Value=\"{Binding Source={StaticResource BackBrush},Converter={StaticResource swapper}}\"/>
</Style>
</Window.Resources>
<Grid Background=\"{StaticResource BackBrush}\">
<TextBlock FontSize=\"24\" FontWeight=\"Bold\">ABC</TextBlock>
</Grid>
</Window>
现在,无论何时更改\'BackBrush \'的颜色值,所有相关的前景色都会自动更新。根据您的讨论,我认为这也将满足您的样式要求。无论如何,您可能必须制作小型mod,以确保此方法适合您的实际情况。