Как расширить вместо переопределения стилей WPF

Я хочу использовать пользовательскую тему в своем приложении и, насколько я знаю, я могу сделать это, используя словарь ресурсов и ссылаясь на него в App.xaml. Стили переопределяют значения по умолчанию следующим образом:

<Style TargetType="{x:Type Label">
    <Setter Property="Foreground" Value="Green" />
</Style>

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

<Grid.Resources>
    <Style TargetType="{x:Type Label">
        <Setter Property="FontSize" Value="28" />
    </Style>
</Grid.Resources>

Все метки в моей сетке теряют свой основной цвет и снова имеют цвет по умолчанию (разве я не переопределял значения по умолчанию на предыдущем шаге?). После некоторых попыток я обнаружил, что для правильного выполнения этой операции мне нужно добавить еще одно свойство Style декларация BasedOn={StaticResource {x:Type Label}}" и это работает. Это немного странно для меня, потому что теперь мне придется повторять один и тот же код BasedOn во всем приложении, а стиль не работает - это следует делать автоматически! Например, в HTML + CSS стили наследуются и объединяются, а в WPF они заменяются...

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

Есть ли способ автоматизировать установку свойства BasedOn? Или, может быть, лучше сделать это в общих чертах?

2 ответа

Решение

У меня такая же проблема. Я использовал ответ Зака ​​и улучшил его следующим образом, так что если вы не укажете стиль, переопределенное значение по умолчанию все равно будет учтено. Это в основном то, что вы бы сделали, но только один раз в ResourceDictionary.

<Window x:Class="TestWpf.RandomStuffWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Random Stuff Window">
  <Window.Resources>
    <ResourceDictionary>
      <!-- Default Label style definition -->
      <Style TargetType="{x:Type Label}">
        <Setter Property="Foreground" Value="Green" />
      </Style>
      <!-- Extending default style -->
      <Style TargetType="{x:Type Label}" 
             x:Key="LargeGreenForegroundLabel" 
             BasedOn="{StaticResource {x:Type Label}}">
        <Setter Property="FontSize" Value="28" />
      </Style>
    </ResourceDictionary>
  </Window.Resources>
  <StackPanel>
    <Button Click="Button_Click">Click</Button>
    <Label Content="GreenForegroundLabel" /> <!-- Uses default style -->
    <Label Style="{StaticResource LargeGreenForegroundLabel}" 
           Content="LargeGreenForegroundLabel" />
  </StackPanel>
</Window>

Wpf имеет разные уровни стилей, которые применяются в порядке глобального> локального. Стиль, установленный непосредственно в элементе управления, переопределит набор стилей глобально, как в вашем примере. Я пытался найти список всех разных мест, в которых элемент управления ищет свои стили, но пока не могу найти его. Насколько я знаю, вам придется использовать свойство BasedOn для наследования стиля и не полностью переопределять свойства этого стиля стилем, установленным вами локально.

Вот пример словаря ресурсов, стили которого основаны на другом стиле, поэтому вам не нужно повторять BasedOn связывая снова и снова, вы можете просто установить стиль на конкретный элемент, который вы хотите иметь этот стиль.

<Window x:Class="TestWpf.RandomStuffWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Random Stuff Window">
  <Window.Resources>
    <ResourceDictionary>
      <Style TargetType="{x:Type Label}" 
             x:Key="GreenForegroundLabel">
        <Setter Property="Foreground" Value="Green" />
      </Style>
      <Style TargetType="{x:Type Label}" 
             x:Key="LargeGreenForegroundLabel" 
             BasedOn="{StaticResource GreenForegroundLabel}">
        <Setter Property="FontSize" Value="28" />
      </Style>
    </ResourceDictionary>
  </Window.Resources>
  <StackPanel>
    <Button Click="Button_Click">Click</Button>
    <Label Style="{StaticResource GreenForegroundLabel}" 
           Content="GreenForegroundLabel" />
    <Label Style="{StaticResource LargeGreenForegroundLabel}" 
           Content="LargeGreenForegroundLabel" />
  </StackPanel>
</Window>
Другие вопросы по тегам