Стиль, чтобы выбрать подходящий передний план в соответствии с цветом фона - PullRequest
1 голос
/ 31 мая 2011

У меня есть приложение 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>

Вы можете видеть, что фон метки выбирается красиво, если для метки задан явный набор фона (x: Name = bgSetExplicitly), но если фон «унаследован» от родителя в VisualTree (x: Name = » bgInheritedFromParent "), это не так. Мне бы очень хотелось, чтобы этот стиль мог оценить «эффективный фон» (независимо от того, откуда он) и выбрать подходящую кисть переднего плана для этого фона.

Ответы [ 3 ]

3 голосов
/ 31 мая 2011

Этот вопрос, кажется, подразумевает более глубокую проблему. Я предполагаю, что вы не консолидировали управление цветами переднего плана, и поэтому у вас есть приложение, в котором есть код или стили, которые устанавливают цвета переднего плана повсюду. И теперь вы имеете дело с одним из последствий этого.

Я бы столкнулся с более глубокой проблемой и решил ее. Я не очень понимаю, почему вы не согласны с идеей создания стилей по умолчанию, но на данный момент предполагаю, что у вас есть веская причина не делать этого (кроме "Я должен был создать стили по умолчанию в какой-то момент, но сейчас что я не сделал, и мое приложение стало большим, это просто слишком сложно (в этом случае у меня есть другое предложение), как насчет создания глобальных ресурсов?

Создайте объекты в словаре ресурсов приложения для цветов переднего плана и фона элементов управления и исправьте XAML так, чтобы вместо прямой ссылки на кисти он использовал расширение разметки DynamicResource для получения их из словаря ресурсов. В коде вместо установки свойства Foreground на элементах управления для кисти, используйте GetResource, чтобы получить кисть. И установить фон таким же образом.

Как только вы это сделаете, если вы хотите глобально изменить цвета переднего плана / фона в вашем приложении, вы просто измените ресурсы.

Это в основном то, как вы начинаете делать скины для приложений WPF, что, кажется, и есть путь, по которому вы идете.

3 голосов
/ 31 мая 2011

Самое простое, что нужно сделать - это привязать цвет переднего плана ваших текстовых полей и т. Д. К фону содержащего их элемента и использовать преобразователь значений для внесения изменений. Это особенно легко, если вы используете только два цвета.

Как пример ....

  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>

Конечно, вы, вероятно, захотите внести некоторые изменения и убрать в соответствии с вашими потребностями, но это будет сделано.

0 голосов
/ 01 июня 2011

Вот еще один возможный подход.Если ваше приложение имеет только ВСЕ темные / светлые фоны и их комплименты, вы можете попробовать такой подход, используя «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', все связанные цвета переднего плана будут автоматически обновлены.Исходя из ваших обсуждений, я думаю, что это также будет соответствовать вашим требованиям стиля.В любом случае вам, вероятно, придется создавать небольшие моды, чтобы этот подход подходил именно вашему сценарию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...