WPF ControlTemplate разбивает стиль
Материал, который работает
Мне нужно стилизовать элементы управления определенного типа, которые являются дочерними элементами StackPanel. Я использую:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type TextBlock}">...</Style>
</StackPanel.Resources>
<TextBlock ...>
...
</StackPanel>
И это отлично работает! Каждый TextBlock ищет ресурсы этого родителя (StackPanel), чтобы узнать, как его следует стилизовать. Не имеет значения, как далеко вы вложите TextBlock в StackPanel... если он не найдет стиль в своем прямом родителе, он будет смотреть на родительский родитель и так далее, пока не найдет что-то (в этом случае, стиль, который был определен в).
Материал, который не работает
У меня возникла проблема, когда я вложил TextBlock внутри ContentControl, у которого был шаблон (см. код ниже). ControlTemplate, похоже, нарушает способ, которым TextBlock получает свой стиль от своих родителей, дедушек и бабушек,...
Использование ControlTemplate эффективно, похоже, выбивает холодное средство TextBlock для поиска его законного стиля (тот, что находится в StackPanel.Resources). Когда он сталкивается с ControlTemplate, он перестает искать свой стиль в ресурсах до дерева и вместо этого по умолчанию использует стиль в MergedDictionaries самого приложения.
<StackPanel Orientation="Vertical" Background="LightGray">
<StackPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green" />
</Style>
</StackPanel.Resources>
<TextBlock Text="plain and simple in stackpanel, green" />
<ContentControl>
<TextBlock Text="inside ContentControl, still green" />
</ContentControl>
<ContentControl>
<ContentControl.Template>
<ControlTemplate TargetType="{x:Type ContentControl}">
<StackPanel Orientation="Vertical">
<ContentPresenter />
<TextBlock Text="how come this one - placed in the template - is not green?" />
</StackPanel>
</ControlTemplate>
</ContentControl.Template>
<TextBlock Text="inside ContentControl with a template, this one is green as well" />
</ContentControl>
</StackPanel>
Есть ли способ - помимо дублирования стиля в StackPanel.Resources для ControlTemplate.Resources - чтобы заставить TextBlock внутри этого элемента управления ControlTemplate найти определенный стиль?
Спасибо...
Ответы
Ответ 1
WPF считает, что ControlTemplates
является границей и не будет применять неявные стили (стили без x:Key
) внутри шаблонов.
Но есть одно исключение из этого правила: все, что наследует от Control
, будет применять неявные стили.
Таким образом, вы можете использовать Label
вместо TextBlock
, и он будет применять неявный стиль, определенный далее в иерархии XAML, однако, поскольку TextBlock
наследует от FrameworkElement
вместо Control
, он выиграл 't применять неявный стиль автоматически, и вы должны добавить его вручную.
Самый распространенный способ обойти это - добавить неявный стиль в ControlTemplate.Resources
, который BasedOn
существующий неявный стиль TextBlock
<ControlTemplate.Resources>
<Style TargetType="{x:Type TextBlock}"
BasedOn="{StaticResource {x:Type TextBlock}}" />
<ControlTemplate.Resources>
Другие распространенные способы обойти это:
-
Поместите неявный стиль в <Application.Resources>
. Стили, размещенные здесь, будут применяться ко всему вашему приложению независимо от границ шаблона. Будьте осторожны с этим, так как он будет применять стиль к TextBlocks
внутри других элементов управления, например, кнопки или ComboBoxes
<Application.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green" />
</Style>
</Application.Resources>
-
Используйте Label
вместо TextBlock
, поскольку он унаследован от Control
, поэтому будут применяться неявные стили, определенные вне ControlTemplate
-
Дайте базовый стиль x:Key
и используйте его как базовый стиль для неявных стилей TextBlock
внутри ControlTemplate
. Это почти то же самое, что и верхнее решение, однако оно используется для базовых стилей, которые имеют атрибут x:Key
<Style x:Key="BaseTextBlockStyle" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Green" />
</Style>
...
<ControlTemplate.Resources>
<Style TargetType="{x:Type TextBlock}"
BasedOn="{StaticResource BaseTextBlockStyle}" />
<ControlTemplate.Resources>