我之所以这样问是因为@Greg D(来自this question)推荐使用SetCurrentValue()
而不是{{1}},而是查看文档并没有看到差异。或者什么“不改变其价值来源”意味着什么呢?
设置依赖项属性的本地值,由其依赖项属性标识符指定。
设置依赖项属性的值而不更改其值源。
答案 0 :(得分:53)
您提供的MSDN链接说得很清楚:
此方法由组件使用 以编程方式设置值 其中一个没有的属性 禁用已声明的应用程序 使用财产。该 SetCurrentValue方法改变了 有效的财产价值,但 现有的触发器,数据绑定和 风格将继续有效。
假设您正在编写TextBox
控件,并且您已经公开了人们经常使用的Text
属性,如下所示:
<TextBox Text="{Binding SomeProperty}"/>
在您的控件代码中,如果您致电SetValue
,您将用您提供的任何内容覆盖绑定。但是,如果您调用SetCurrentValue
,则会确保该属性采用给定值,但不会销毁任何绑定。
据我所知,格雷格的建议不正确。您应始终使用CLR包装器属性中的GetValue
/ SetValue
。 SetCurrentValue
在需要属性获取给定值但不想覆盖已针对您的属性配置的任何绑定,触发器或样式的场景中更有用。
答案 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
讨论:
缺少DependencyProperty
为'42'的DefaultValue
的初始状态具有声明的BaseValueSource.Default
标志。 ReadLocalValue()
返回全局单例实例DependencyProperty.UnsetValue
。
SetValue()
在内部存储BaseValueSource.Local
值,如预期。
使用SetValue
存储恰好等于DefaultValue
的值不会恢复BaseValueSource.Default
状态(与下面的#6比较)。
相反,如果要删除任何/所有存储的值或绑定并将DP恢复到原始状态,请调用ClearValue()
。 (请参见下面的注释)
对于SetCurrentValue()
,属性值是通过强制产生的,而无需声明BaseValueSource.Local
模式。请注意,尽管该属性现在报告的值为 not (实际上等于该值),但先前的BaseValueSource
默认仍然有效DefaultValue
。
重要提示:
这意味着检查BaseValueSource
返回的GetValueSource()
是否等于BaseValueSource.Default
是 可靠的指标,用于确定主要属性值是否是DP元数据中的默认值。
SetCurrentValue
会 根据DP元数据的{{1}检查是否相等},为了删减值,它也因此认为多余是“不必要的”。急于进行清理的目的可能是减轻DP存储的膨胀,但同时也会使DP状态的透明性与特殊情况下的“非屏蔽”行为复杂化,如果不彻底理解,可能会导致模糊的错误。例如,#6将DP清除回与DefaultValue
...无法区分的原始状态。
...但仅 ,前提是先前存储的ClearValue()
是BaseValueSource
而非Current
;将#5 /#6与#7对进行比较,尽管报告的属性值相同,但内部状态标志却大不相同。
关于Local
:
很明显,ClearValue()
不会被任何PropertyChangedCallback
操作调用,而这些操作最终不会导致该属性的先前值发生变化。这是根本原因,因为SetValue()
隐含一个假设,即正在进行的更改与工作中的活动资产的价值有关。不太直观的是,同样的逻辑也适用于SetValue
。
例如,在#4中,ClearValue()
导致从内部DP存储中删除本地值ClearValue
,以及其他内部状态更改,所有操作均符合预期。问题在于,在当前42
调用期间,是否调用OnPropertyChanged
取决于先前的值< em> 已变为等于 元数据默认值。
由于“清除”操作的语义似乎暗示了先前状态的摘要丢弃-因此,通常假定“ ClearValue
”的行为取决于上下文/任意状态,在ClearValue()
的行为取决于某个/任何先前状态的情况下,可能不会想到这种不一致。特别是对于还牵涉(和混合)新状态的重大行为,例如是否触发“更改”通知。