问题
Why is it that some dependency properties need to have a default setter in the style before the triggered setters will take effect?
For example,
<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>
I saw a good explanation of it somewhere, but I can't remember where. I recall it had something to do with the order that WPF applies dependency property values, but I can't remember the details, or why some properties need the default defined before triggers will take effect, while others do not.
回答1:
I would be very surprised if your first Style
does not work, unless your ContentControl
is defined like:
<ContentControl ContentTemplate="{StaticResource DefaultTemplate}" />
If so, then it would have to do with value precedence. From your link, setting like in my example would be at #3. So the only thing that could override it would be an animation or if the value were coerced. Neither the Style
or the ControlTemplate
(if any) could change the ContentControl.ContentTemplate
property.
With your second Style
, you could define your ContentControl
like so:
<ContentControl />
In this case, the Setter
for DefaultTemplate
is at #8 so the triggers can override it (as they are at #6).
Assuming again, that you have:
<ContentControl ContentTemplate="{StaticResource DefaultTemplate}" />
Then it is possible to override the DataTemplate
used in the ControlTemplate
, but you cannot change the ContentControl.ContentTemplate
's value. Something like:
<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>
Here, we switch the DataTemplate
used by the ContentPresenter so it effectively ignores the ContentControl.ContentTemplate
property.
Based on your updates though, there is nothing for the mouse to be "over". The ContentControl has not rendered anything (not even a transparent pixel), so it would not receive any mouse events. You can do something like this to correct it:
<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>
And you'd need to set Background="Transparent" on the ContentControl.
来源:https://stackoverflow.com/questions/7795587/why-do-some-properties-need-a-default-defined-in-the-style-before-a-datatrigger