Как расширить вместо переопределения стилей 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>