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

Я хочу использовать пользовательскую тему в своем приложении, и, насколько я знаю, я могу это сделать, используя словарь ресурсов и ссылаясь на него в приложении.код 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 их заменяют...

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

есть ли способ автоматизировать настройку свойства 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 имеет разные уровни стилей, которые применяются в порядке global > local. Набор стилей непосредственно в элементе управления переопределит набор стилей глобально, как в вашем примере. Я пытался найти список всех различных мест, которые элемент управления ищет для своих стилей, но я не могу найти его на данный момент. Насколько я знаю, вам нужно будет использовать свойство 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>