#wpf #xaml #dependency-properties
#wpf #xaml #зависимость-свойства
Вопрос:
Почему некоторым свойствам зависимостей необходимо иметь параметр по умолчанию в стиле, прежде чем сработавшие параметры вступят в силу?
Например,
<ContentControl>
<ContentControl.Resources>
<DataTemplate x:Key="DefaultTemplate">
<TextBlock Text="Default Template" />
</DataTemplate>
<DataTemplate x:Key="MouseOverTemplate">
<TextBlock Text="MouseOver Template" />
</DataTemplate>
</ContentControl.Resources>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<!-- Triggered setter will work without this default setter -->
<!--<Setter Property="ContentTemplate"
Value="{StaticResource DefaultTemplate}" />-->
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ContentTemplate"
Value="{StaticResource MouseOverTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
Я где-то видел хорошее объяснение этого, но не могу вспомнить где. Я помню, что это как-то связано с порядком, в котором WPF применяет значения свойств зависимостей, но я не могу вспомнить детали или почему некоторым свойствам требуется значение по умолчанию, определенное до того, как триггеры вступят в силу, а другим нет.
Ответ №1:
Я был бы очень удивлен, если ваш первый Style
не будет работать, если ваш ContentControl
не определен как:
<ContentControl ContentTemplate="{StaticResource DefaultTemplate}" />
Если это так, то это должно быть связано с приоритетом значений. По вашей ссылке настройка, подобная в моем примере, будет находиться на # 3. Таким образом, единственное, что могло бы переопределить это, была бы анимация или если бы значение было принудительно введено. Ни Style
или ControlTemplate
(если таковые имеются) не могут изменить ContentControl.ContentTemplate
свойство.
С вашим вторым Style
вы могли бы определить свой ContentControl
подобный:
<ContentControl />
В этом случае Setter
for DefaultTemplate
находится на # 8, поэтому триггеры могут переопределить его (как и на # 6).
Опять же, предполагая, что у вас есть:
<ContentControl ContentTemplate="{StaticResource DefaultTemplate}" />
Тогда можно переопределить DataTemplate
используемое в ControlTemplate
, но вы не можете изменить значение ContentControl.ContentTemplate
‘s . Что-то вроде:
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ControlTemplate">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<ContentPresenter x:Name="presenter" />
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding SomeProperty}" Value="A">
<Setter TargetName="presenter" Property="ContentTemplate" Value="{StaticResource TemplateA}" />
</DataTrigger>
<DataTrigger Binding="{Binding SomeProperty}" Value="B">
<Setter TargetName="presenter" Property="ContentTemplate" Value="{StaticResource TemplateB}" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Здесь мы переключаем DataTemplate
используемый ContentPresenter, чтобы он эффективно игнорировал ContentControl.ContentTemplate
свойство.
Однако, основываясь на ваших обновлениях, мышь не должна быть «над». ContentControl ничего не отобразил (даже прозрачный пиксель), поэтому он не получит никаких событий мыши. Вы можете сделать что-то вроде этого, чтобы исправить это:
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource MouseOverTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
И вам нужно будет установить Background=»Transparent» в ContentControl .
Комментарии:
1. Первый стиль не работает. Попробуйте с помощью простого
IsMouseOver
триггера.2. @Rachel — Как вы определяете этот триггер? Это не сработает
{Binding IsMouseOver}
, поскольку это относится к DataContext, но это должно сработать{Binding IsMouseOver, RelativeSource={RelativeSource Self}}
.3. Hrrm вы правы в том, что в этом случае это не работает из-за отсутствия содержимого, но я видел такое поведение с другими установщиками стилей. Давайте посмотрим, смогу ли я найти лучший пример.
4. Я начинаю думать, что я ошибаюсь. Я знаю, что несколько раз я сталкивался с триггерами, которые не работали, если я не добавлял установщик стиля по умолчанию, хотя прошло некоторое время с тех пор, как я в последний раз сталкивался с этой проблемой, и с тех пор всегда добавлял установщик по умолчанию в свои триггеры. Вполне возможно, что мой XAML был ошибочным или что это была ошибка в более старой версии . Net framework. Пока принимаю ваш ответ, поскольку более вероятно, что причиной моих проблем был некорректный XAML, но если я найду хороший пример этой проблемы, я снова открою вопрос с вознаграждением 🙂