根据背景颜色选择合适的前景的样式

时间:2011-05-31 10:41:40

标签: wpf styles background-color foreground

我有一个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“),它不是。 我希望有这样的工作,风格可以评估“有效背景”(无论它来自何处),并为此背景选择合适的地上画笔。

3 个答案:

答案 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以确保此方法适合您的确切方案。