为什么某些属性需要在 DataTrigger 生效之前在样式中定义默认值?

发布于 2024-12-10 12:10:59 字数 1347 浏览 0 评论 0原文

为什么有些依赖属性需要在样式中有一个默认的setter,触发的setter才会生效?

例如,

<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应用依赖属性值的顺序,但我不记得细节,或者为什么有些属性需要在触发器生效之前定义默认值,而其他属性则不需要。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

初熏 2024-12-17 12:10:59

如果您的第一个 Style 不起作用,我会感到非常惊讶,除非您的 ContentControl 定义如下:

<ContentControl ContentTemplate="{StaticResource DefaultTemplate}" />

如果是这样,那么它将与值优先级有关。从您的链接中,像我的示例中那样的设置将位于#3。因此,唯一可以覆盖它的是动画或者该值是否被强制。 StyleControlTemplate(如果有)都无法更改 ContentControl.ContentTemplate 属性。

使用第二个 Style,您可以像这样定义 ContentControl

<ContentControl />

在本例中,DefaultTemplateSetter 是在 #8 处,因此触发器可以覆盖它(就像在 #6 处一样)。

再次假设您:

<ContentControl ContentTemplate="{StaticResource DefaultTemplate}" />

那么可以覆盖 ControlTemplate 中使用的 DataTemplate,但无法更改 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>

在这里,我们切换 ContentPresenter 使用的 DataTemplate,以便它有效地忽略 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>

并且您需要在 ContentControl 上设置 Background="Transparent"。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文