【问题标题】:Can you determine the source of an inheritable Attached Property?你能确定一个可继承的附加属性的来源吗?
【发布时间】:2012-05-29 21:09:22
【问题描述】:

我们有两个外部定义的、逻辑上独占(业务方面)的附加属性,它们都是可继承的。取决于哪个设置最接近我们正在阅读的 DependencyObject,这决定了我们在逻辑中使用哪个,如下所示。

注意:我不想知道它继承的,你可以通过DependencyPropertyHelper.GetValueSource 来做,我想知道从哪里开始,所以我可以确定优先级。

考虑以下可视树层次结构和附加属性:

Root // <-- AProp1 first set here
    Child
        GrandChild // <-- AProp2 first set here
            GreatGrandChild // <-- AProp1 re-applied here
                GreatGreatGrandChild
  • 在 Root 的情况下,AProp1 是单独设置的,因此我们使用 AProp1。

  • 在 Child 的情况下,AProp1 是继承的,因此我们仍然使用 AProp1。

  • 在 GrandChild 的情况下,设置了 AProp2,但由于继承,AProp1 也具有值。但是,由于 AProp2 直接设置在此对象上(即距离“0”级的距离)与 AProp1(距离“2”的距离),因此 AProp2 优先于我们的业务逻辑。

  • 在 GreatGrandChild 的情况下,同样由于 AProp1 已设置(距离为“0”),它优先于 AProp2(距离为“1”)

  • 最后,在 GreatGreatGrandChild 的情况下,AProp1 和 AProp2 都是通过继承获取的,但是由于 AProp1 在层次结构中设置得更近(距离为“1”)与 AProp2(距离为“2”) , AProp1 就是我们要使用的那个。

如果我能找到源头,我知道我可以简单地走链条并计算距离。我只需要源代码。

注意:

为了记录,是的,它们都可以设置在同一级别,在这种情况下 AProp2 将优先,但这与这个问题无关。

即使使用 same 值作为提高其优先级的一种方式,也可以重新应用属性(请参阅 GreatGrandChild)。这就是为什么我需要知道源在哪里/离我正在检查的元素有多远。

【问题讨论】:

    标签: wpf inheritance dependency-properties attached-properties


    【解决方案1】:

    一个非常有趣的问题!您可以将附加属性添加到存储类型的 DependencyObject(如果类型对您不利,您可以存储对象引用),我们将使用它来记录设置该属性的对象的类型。

     public class DependencyPropertyExtension
        {
            public static Type GetAprop1Owner(DependencyObject obj)
            {
                return (Type)obj.GetValue(Aprop1OwnerProperty);
            }
    
            public static void SetAprop1Owner(DependencyObject obj, Type value)
            {
                obj.SetValue(Aprop1OwnerProperty, value);
            }
    
            public static readonly DependencyProperty Aprop1OwnerProperty = DependencyProperty.RegisterAttached("Aprop1Owner", typeof(Type), typeof(DependencyProperty), new UIPropertyMetadata(null));
        }
    

    然后在依赖属性 Aprop1 中添加一些 UIPropertyMetaData 以便我们可以响应更新。

    public object Aprop1
    {
        get { return (object)GetValue(Aprop1Property); }
        set { SetValue(Aprop1Property, value); }
    }
    public static readonly DependencyProperty Aprop1Property =
        DependencyProperty.Register("Aprop1", typeof(object), typeof(Level1), new UIPropertyMetadata(null, new PropertyChangedCallback( (s, e) =>
            {
                DependencyPropertyExtension.SetAprop1Owner(s, s.GetType());
            })));
    

    我在这里所做的只是将附加属性更新为设置属性的对象的类型。

    您可以使用

    从任何对象中读取此信息
    DependencyPropertyExtension.GetAprop1Owner(testObject).FullName
    

    【讨论】:

    • 是的,Type 绝对不能告诉你足够的信息(实际上是什么),但正如你所说,你可以使用实例。不过,不确定您的新财产是否必须具有继承权才能工作?此外,我们确实无法访问我们正在设置的属性,因此我们不能简单地更改元数据,但是您给了我一个想法……我们在内部使用 our 属性在 our 更改处理程序中设置 他们的 属性。我们可以控制。 Atill,我投票给你是因为你的投票让我得出了似乎可行的结论。 (我只是写一个附加的方法来获取距离。)
    • 其实,想到了更好的办法。 (如果你愿意的话,一个'Duh!'时刻。)发布我的答案。
    【解决方案2】:

    我想我已经找到了。那些“一直摆在你面前”的东西之一。它围绕使用DependencyPropertyHelper.GetValueSource 来确定对象的属性值是否被继承。

    当然,这本身并不足以告诉你,但从那里开始很容易。

    有了这些知识,您只需编写一个接收相关对象并检查两个属性是否存在的方法(请记住,它们可能由于默认值、样式、模板或其他原因而被“设置”)并继续相应地:

    • 如果只设置了两个中的一个,那就是你使用的那个,你就完成了。根据需要处理。

    • 如果它们都已设置,则使用单个属性使用的相同优先级。 (即LocalInheritInheritDefault 等)您只是在同一级别上比较两个属性源的值。

    • 如果它们的来源相同且不是Inherit,则使用业务逻辑中优先的那个(在我们的例子中为 AProp2。)

    • 如果它们相同并且 Inherit,则您沿着逻辑树(或可视化,具体取决于您的需要)并递归调用传入父级的相同函数。

    当然,如果这个属性受动画和其他类似的东西的影响,那么逻辑会变得有点复杂,但在我们的例子中,它要么在本地设置,要么被继承。其他不多。

    现在很简单,我正在看它。希望这对其他人有帮助!

    【讨论】:

      【解决方案3】:

      使用元组来包含这两个值。最接近的继承属性将包含一个值或另一个值,它将优先。

      您无需反映整个可视化树,并依赖于依赖属性的内置机制。

      【讨论】:

      • 请举例。不确定您的解决方案将如何与我发布的场景一起工作。
      猜你喜欢
      • 2011-03-31
      • 2017-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 2015-08-13
      相关资源
      最近更新 更多