Why do some properties need a default defined in the style before a DataTrigger takes effect?

蓝咒 提交于 2020-01-13 03:22:27

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!