Dependency Property SetValue()&之间有什么区别? SetCurrentValue()

时间:2010-11-20 01:11:51

标签: wpf dependency-properties setvalue setcurrentvalue

我之所以这样问是因为@Greg D(来自this question)推荐使用SetCurrentValue()而不是{{1}},而是查看文档并没有看到差异。或者什么“不改变其价值来源”意味着什么呢?

SetValue()

设置依赖项属性的本地值,由其依赖项属性标识符指定。

SetCurrentValue()

设置依赖项属性的值而不更改其值源。

3 个答案:

答案 0 :(得分:53)

您提供的MSDN链接说得很清楚:

  

此方法由组件使用   以编程方式设置值   其中一个没有的属性   禁用已声明的应用程序   使用财产。该   SetCurrentValue方法改变了   有效的财产价值,但   现有的触发器,数据绑定和   风格将继续有效。

假设您正在编写TextBox控件,并且您已经公开了人们经常使用的Text属性,如下所示:

<TextBox Text="{Binding SomeProperty}"/>

在您的控件代码中,如果您致电SetValue,您将用您提供的任何内容覆盖绑定。但是,如果您调用SetCurrentValue,则会确保该属性采用给定值,但不会销毁任何绑定。

据我所知,格雷格的建议不正确。您应始终使用CLR包装器属性中的GetValue / SetValueSetCurrentValue在需要属性获取给定值但不想覆盖已针对您的属性配置的任何绑定,触发器或样式的场景中更有用。

答案 1 :(得分:2)

继续接受的答案:

我发现this post很好地解释了SetCurrentValue()。请注意依赖项属性值优先级系统如何在绑定值上获取本地值。这解释了评论者的意外行为。

答案 2 :(得分:1)

演示工具(完整):

class test : DependencyObject
{
    static DependencyProperty XyzProperty =
        DependencyProperty.Register("Xyz", typeof(int), typeof(test), new PropertyMetadata(42));

    public test()
    {
        /* ... see code shown below ... */
    }

    void inf()
    {
        var info = DependencyPropertyHelper.GetValueSource(this, XyzProperty);
        var msg = $@"{"//"
                   } {(int)GetValue(XyzProperty),2
                   } {(ReadLocalValue(XyzProperty) is int x ? "(Object)" + x : "UnsetValue"),12
                   } {info.BaseValueSource,9
                   } {(info.IsCurrent ? "" : "Not") + "Current",12
                   } {(info.IsCoerced ? "" : "Not") + "Coerced",12
                   }";
        Trace.WriteLine(msg);
    }
};

讨论示例:

                                      // v̲a̲l̲u̲e̲  s̲t̲o̲r̲e̲d̲-o̲b̲j̲      B̲V̲S̲    C̲u̲r̲r̲e̲n̲t̲?    C̲o̲e̲r̲c̲e̲d̲?
/*1*/                                    // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*2*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced

/*3*/ SetValue(XyzProperty, 42);         // 42  (Object)42    Local  NotCurrent  NotCoerced

/*4*/ ClearValue(XyzProperty);           // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*5*/ SetCurrentValue(XyzProperty, 5);   //  5   (Object)5  Default     Current     Coerced

/*6*/ SetCurrentValue(XyzProperty, 42);  // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*7*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced
      SetCurrentValue(XyzProperty, 42);  // 42  (Object)42    Local     Current     Coerced

讨论:

  1. 缺少DependencyProperty为'42'的DefaultValue的初始状态具有声明的BaseValueSource.Default标志。 ReadLocalValue()返回全局单例实例DependencyProperty.UnsetValue

  2. SetValue()在内部存储BaseValueSource.Local值,如预期。

  3. 使用SetValue存储恰好等于DefaultValue的值不会恢复BaseValueSource.Default状态(与下面的#6比较)。

  4. 相反,如果要删除任何/所有存储的值或绑定并将DP恢复到原始状态,请调用ClearValue()。 (请参见下面的注释)

  5. 对于SetCurrentValue(),属性值是通过强制产生的,而无需声明BaseValueSource.Local模式。请注意,尽管该属性现在报告的值为 not (实际上等于该值),但先前的BaseValueSource 默认仍然有效DefaultValue

重要提示:
这意味着检查BaseValueSource返回的GetValueSource()是否等于BaseValueSource.Default 可靠的指标,用于确定主要属性值是否是DP元数据中的默认值。

    另一方面,与上面的#3不同,
  1. SetCurrentValue 根据DP元数据的{{1}检查是否相等},为了删减值,它也因此认为多余是“不必要的”。急于进行清理的目的可能是减轻DP存储的膨胀,但同时也会使DP状态的透明性与特殊情况下的“非屏蔽”行为复杂化,如果不彻底理解,可能会导致模糊的错误。例如,#6将DP清除回与DefaultValue ...无法区分的原始状态。

  2. ...但仅 ,前提是先前存储的ClearValue()BaseValueSource而非Current;将#5 /#6与#7对进行比较,尽管报告的属性值相同,但内部状态标志却大不相同。

关于Local

很明显,ClearValue()不会被任何PropertyChangedCallback操作调用,而这些操作最终不会导致该属性的先前值发生变化。这是根本原因,因为SetValue()隐含一个假设,即正在进行的更改与工作中的活动资产的价值有关。不太直观的是,同样的逻辑也适用于SetValue

例如,在#4中,ClearValue()导致从内部DP存储中删除本地值ClearValue,以及其他内部状态更改,所有操作均符合预期。问题在于,在当前42调用期间,是否调用OnPropertyChanged 取决于先前的值< em> 已变为等于 元数据默认值。

由于“清除”操作的语义似乎暗示了先前状态的摘要丢弃-因此,通常假定“ ClearValue”的行为取决于上下文/任意状态,在ClearValue()的行为取决于某个/任何先前状态的情况下,可能不会想到这种不一致。特别是对于还牵涉(和混合)状态的重大行为,例如是否触发“更改”通知。