【问题标题】:WPF dependency property precedence - the templated parentWPF 依赖属性优先级 - 模板化父级
【发布时间】:2011-05-13 04:33:50
【问题描述】:

list of sources for dependency property values 中,与相对优先级一起,本地值是确定基值的最高优先级。
紧跟在本地值之后的是来自模板化父级的模板属性——例如在模板上下文中创建的控件的父 ControlTemplate。

我的问题是——由于本地值被列为优先于模板属性,这是否意味着在模板中创建的控件上显式设置的属性值(本地值)优先于具有该模板中的属性触发器?这似乎是规则所暗示的,但在控件模板中使用触发器设置的属性似乎会覆盖(即更高优先级)在模板中设置的本地值。

或者优先级列表中的“本地值”是指仅在未在模板中创建的控件上设置的值 - 因此您无法真正比​​较本地值和通过模板中的触发器设置的属性之间的优先级父母?

【问题讨论】:

    标签: wpf properties dependencies


    【解决方案1】:

    是的,优先列表中的“本地值”仅指在模板之外的元素上设置的属性。优先级列表的相关部分是4b:

    4。 TemplatedParent 模板属性。一个元素有一个 TemplatedParent 如果它被创建为 模板的一部分(一个 ControlTemplate 或数据模板)。有关何时的详细信息 这适用,请参阅 TemplatedParent 稍后在本主题中。内 模板,以下优先级 适用:

    一个。来自 TemplatedParent 的触发器 模板。

    b.属性集(通常通过 XAML 属性)在 TemplatedParent 模板。

    模板中设置的属性值的优先级低于模板中的触发器,并且两者的优先级都低于本地值。

    您可以通过调用DependencyPropertyHelper.GetValueSource 并检查 BaseValueSource 属性来查看值是如何设置的。在模板外设置的值将具有“Local”源,而在模板内设置的值将具有“ParentTemplate”源。

    将它们作为单独的源还意味着属性系统可以分别跟踪本地值和父模板值。如果您在具有模板值的属性上设置本地值,然后调用ClearValue,它将恢复为模板设置的值。


    这是一个示例,它演示了覆盖模板中的值的本地值。使用下面的代码创建一个 UserControl 并将其添加到 Window。它有一个蓝色矩形,当鼠标在控件上方时会变为绿色。如果单击“设置”,代码将在矩形上设置一个本地值,该值将覆盖这两个值。如果单击“清除”,它将清除本地值并从模板中恢复值。您可以单击“显示”以查看当前值源(您需要使用键盘按下按钮才能查看 ParentTemplate,因为将鼠标悬停在按钮上会触发触发器)。

    XAML:

    <UserControl
        x:Class="WpfApplication1.UserControl1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <UserControl.Template>
            <ControlTemplate>
                <StackPanel Background="Transparent">
                    <Button Click="Display_Click" Content="Display"/>
                    <Button Click="Set_Click" Content="Set"/>
                    <Button Click="Clear_Click" Content="Clear"/>
                    <Rectangle Width="100" Height="100"
                               Fill="Blue" Name="PART_Rectangle"/>
                </StackPanel>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="PART_Rectangle"
                                Property="Fill" Value="Green"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </UserControl.Template>
    </UserControl>
    

    代码隐藏:

    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            rectangle = Template.FindName("PART_Rectangle", this) as Rectangle;
        }
    
        private Rectangle rectangle;
    
        private void Display_Click(object sender, RoutedEventArgs e)
        {
            var source = DependencyPropertyHelper.GetValueSource(
                rectangle, Rectangle.FillProperty);
            MessageBox.Show(string.Format("Value {0}; Source {1}",
                rectangle.Fill, source.BaseValueSource));
        }
    
        private void Set_Click(object sender, RoutedEventArgs e)
        {
            rectangle.Fill = Brushes.Red;
        }
    
        private void Clear_Click(object sender, RoutedEventArgs e)
        {
            rectangle.ClearValue(Rectangle.FillProperty);
        }
    }
    

    【讨论】:

    • 感谢您的回答。 “这两者的优先级都低于本地值”-我需要通过一些示例来解决一些问题,但是从我迄今为止尝试过的所有内容来看,通过模板中的属性触发器设置的值似乎覆盖了本地值在模板外的元素上。 IE。我似乎无法重现 4a 或 4b(模板属性)的优先级低于 3(本地值)的场景。模板属性值总是覆盖本地值。
    • @Sean:我在答案中添加了一个简单的示例,它将展示本地值的更高优先级。
    • 谢谢——非常详细,你的例子很容易看出三者之间的优先级——你的初始蓝色有 ParentTemplate 的来源,当你通过触发器更改时变成 ParentTemplateTrigger,然后变成 Local 当您通过代码设置。
    • 我没想过尝试通过代码设置 prop 来查看本地值的示例。我试图通过 XAML 进行设置,但在 XAML 中,模板本身中设置的任何道具都不会被视为本地值,但来源是 ParentTemplate。然后尝试在应用模板的父元素上设置一个 prop 并没有真正起作用,因为该父元素被模板中的子元素完全替换。
    • 例如如果您不是使用 UserControl,而是从 Button 开始并将模板应用于 Button,那么您将丢失在父 Button 上设置的任何本地 props,除非您使用 TemplateBinding 表达式将值显式拉入模板中——但随后您将根本不是在谈论相同的属性,只是将外部/父属性值复制到内部/子项中。无论如何,再次感谢——很好的例子。
    猜你喜欢
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 2012-10-22
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 2017-04-14
    相关资源
    最近更新 更多