我有一个WPF应用程序,它附带了一组由项目类型定义的Label,TextBox等的默认样式(没有定义明确的键)。
在应用程序中,使用了两个主要容器,一个具有深色背景,另一个具有浅色背景,因此有时使用黑色作为标签的前景颜色是正确的,有时其显着错误。另一方面,编辑器总是采用浅色背景和深色前景进行传统设计,因此我不能将所有子元素的前景设置为反向。
是否有一种优雅的方式来制作我的标签(也可能是TextBlocks)来决定它们的前景颜色取决于“他们的”背景?我只想在两种颜色之间切换,因此不需要自动对比度最大化,只需要一些阈值来避免白底上的白色字体。
我也不想定义两组默认样式,我强烈寻找一些方法让我的单一Label-Default-Style适合两种背景变体。
是否有可能(并且在没有太多性能影响的情况下可行)为样式添加触发器/绑定,以评估当前的背景颜色?
或者,我会对如何为某些FrameworkElements(尤其是容器/面板)干净地设置背景颜色的最佳实践感兴趣,而不会遇到上述问题。
这是我尝试过的(当然简化):
<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中的父项'继承'(x:Name =“),则可以看到标签的背景很好地选择bgInheritedFromParent“),它不是。 我希望有这样的工作,风格可以评估“有效背景”(无论它来自何处),并为此背景选择合适的地上画笔。
答案 0 :(得分:3)
最简单的方法是将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>
当然,您可能希望根据您的具体需求进行一些调整和清理,但这样做。
答案 1 :(得分:3)
这个问题似乎意味着更深层次的问题。我猜你没有巩固前景色的管理,所以你有一个应用程序,它有代码或样式,可以在整个地方设置前景色。而现在你正在处理其中一个含义。
我将面对更深层次的问题并解决这个问题。我真的不明白为什么你对创建默认样式的想法有所抵制,但是暂时假设你有充分的理由不这样做(除了“我应该在某些时候创建默认样式,但现在我没有,我的应用程序变得很大,这太难了,“在这种情况下,我有不同的建议),如何创建全球资源?
在应用程序的资源字典中为控件的前景色和背景色创建对象,并修复XAML,以便不使用DynamicResource
标记扩展来代替直接引用画笔,而是从资源字典中获取它们。在代码中,不是直接将控件的Foreground
属性设置为画笔,而是使用GetResource
来获取画笔。并以相同的方式设置背景。
完成此操作后,如果要在应用程序中全局更改前景/背景颜色,只需更改资源即可。
这基本上就是你开始制作一个可换肤的WPF应用程序,这似乎是你要走的路。
答案 2 :(得分:0)
这是另一种可能的方法。如果您的应用程序只有所有深色/浅色背景及其赞美,您可以使用我在其他答案中提到的“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以确保此方法适合您的确切方案。