#wpf #xaml #styles #themes #derived
#wpf #xaml #стили #темы #производный
Вопрос:
Я пытаюсь работать и понимать иерархию XAML для стилей… в простом, простом текстовом поле … повсюду видно, как установить «отключенный» цвет фона на основе флага «IsEnabled». Отлично, понял.
Теперь я хочу иметь другой класс, производный от TextBox… MyTextBox. Для этого класса у меня есть свойство (не свойство зависимости, поэтому я использовал DataTrigger). Итак, я хочу сохранить все обычные действия с текстовым полем, которые работали, но теперь получите новый триггер для правильного обновления цвета фона на какой-либо другой цвет.. Итак, вот что у меня есть. просто чтобы уточнить, все мои статические ресурсы для цветов — СПЛОШНЫЕ КИСТИ…
<Style TargetType="TextBox" >
<Setter Property="FontFamily" Value="Courier New" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Foreground" Value="{StaticResource MyForeground}" />
<Setter Property="Background" Value="{StaticResource MyBackground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border Name="Bd" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<ScrollViewer Name="PART_ContentHost"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{StaticResource MyDisBackground}" />
<Setter TargetName="PART_ContentHost" Property="Background"
Value="MyDisBackground"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Now, my derived (or so I was hoping) style that just adds additional trigger -->
<Style TargetType="local:MyTextBox" BasedOn="{StaticResource {x:Type TextBox}}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsRequired}" Value="True">
<Setter Property="Background" Value="{StaticResource RequiredBackground}" />
</DataTrigger>
</Style.Triggers>
</Style>
Я упускаю что-то простое?
Ответ №1:
Во-первых, вы DataTrigger
смотрите на DataContext
свой MyTextBox
(а не на сам элемент управления). Итак, посмотрите на элемент управления, вам нужно будет сделать что-то вроде:
<DataTrigger Binding="{Binding Path=IsRequired, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Background" Value="{StaticResource RequiredBackground}" />
</DataTrigger>
Теперь это установит MyTextBox.Background
свойство, когда MyTextBox.IsRequired
оно равно true. Но значения свойств зависимостей имеют порядок приоритета. Таким образом, вышеизложенное визуально изменит используемый фон, например:
<local:MyTextBox />
В следующем случае ваша RequiredBackground
кисть использоваться не будет. Вместо этого вы увидите MyDisBackground
кисть:
<local:MyTextBox IsEnabled="False" />
В этом случае значение ScrollViewer.Background
изменяется на MyDisBackground
и больше не привязывается к MyTextBox.Background
свойству. Все MyTextBox.Background
равно будет RequiredBackground
, но он больше нигде не используется.
Наконец, в следующем случае ваша RequiredBackground
кисть использоваться не будет.
<local:MyTextBox Background="Yellow" />
Здесь локальное значение (желтое) находится на # 3 в списке приоритетов, в то время как параметр установки стиля находится на # 8.
Если вы создадите для своего свойства свойство зависимости, значение которого по умолчанию равно false, вы можете сделать что-то вроде:
<Style TargetType="TextBox" >
<Setter Property="FontFamily" Value="Courier New" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Foreground" Value="{StaticResource MyForeground}" />
<Setter Property="Background" Value="{StaticResource MyBackground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border Name="Bd" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<ScrollViewer Name="PART_ContentHost"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="local:MyTextBox.IsRequired" Value="False">
<Setter Property="Background" Value="{StaticResource RequiredBackground}" />
<Setter TargetName="PART_ContentHost" Property="Background"
Value="RequiredBackground"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{StaticResource MyDisBackground}" />
<Setter TargetName="PART_ContentHost" Property="Background"
Value="MyDisBackground"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:MyTextBox" BasedOn="{StaticResource {x:Type TextBox}}" />
Несмотря на то, что свойство не существует для текстового поля, оно все равно может получить значение по умолчанию для вашего свойства зависимости и активировать его. Но поскольку он будет установлен для текстового поля, этот триггер никогда не будет использоваться.
Комментарии:
1. Что ж, я скопировал ваш код и внес первое предложенное изменение, в котором в CodeNaked указано Binding=»{Путь привязки = IsRequired, RelativeSource={RelativeSource Self}}» Это изменение само по себе, похоже, сработало (при условии, что ваш класс ‘MyTextBox’ реализует INotifyPropertyChanged с вашим свойством IsRequired . Я бы опубликовал свой код, чтобы показать вам, что именно я сделал… но я не хочу публиковать конкурирующий ответ, поскольку я не был тем, кто действительно его придумал.
2. @Scott, спасибо за оба ваших ввода, похоже, они работают так, как я надеялся, и посмотрите, как в ОБОИХ условиях… один как DependencyProperty, другой через INotifyPropertyChanged (который у меня уже был)
3. @DRapp, рад видеть, что ваше решение работает! Из двух решений, которые у вас есть… Я определенно предпочитаю решение свойств зависимостей, поскольку затем вы можете устанавливать значения непосредственно в XAML. Я только что заметил, что вы конкретно указали в своем вопросе, что вы не используете DependencyProperty и поэтому предположили, что вы предпочитаете избегать этого.