Wpf 什么';s依赖项属性SetValue()和;SetCurrentValue()
我之所以问这个问题,是因为@Greg D(from)建议我改为使用Wpf 什么';s依赖项属性SetValue()和;SetCurrentValue(),wpf,dependency-properties,setvalue,setcurrentvalue,Wpf,Dependency Properties,Setvalue,Setcurrentvalue,我之所以问这个问题,是因为@Greg D(from)建议我改为使用SetCurrentValue(),但是看一下文档,没有发现有什么区别。或者“不改变其价值来源”是什么意思 设置依赖项属性的本地值,该值由其 依赖属性标识符 设置依赖项属性的值而不更改其值 来源 您提供的MSDN链接很好地说明了这一点: 此方法由组件使用 以编程方式设置值 属于它自己的一种财产,没有 禁用应用程序声明的 财产的使用。这个 SetCurrentValue方法更改 财产的有效价值,但 现有触发器、数据绑定和 风格将
SetCurrentValue()
,但是看一下文档,没有发现有什么区别。或者“不改变其价值来源”是什么意思
设置依赖项属性的本地值,该值由其
依赖属性标识符
设置依赖项属性的值而不更改其值
来源
您提供的MSDN链接很好地说明了这一点: 此方法由组件使用 以编程方式设置值 属于它自己的一种财产,没有 禁用应用程序声明的 财产的使用。这个 SetCurrentValue方法更改 财产的有效价值,但 现有触发器、数据绑定和 风格将继续发挥作用 假设您正在编写
TextBox
控件,并且您公开了人们经常使用的Text
属性,如下所示:
<TextBox Text="{Binding SomeProperty}"/>
在控件的代码中,如果调用SetValue
,您将用您提供的任何内容覆盖绑定。但是,如果调用SetCurrentValue
,将确保属性接受给定的值,但不会破坏任何绑定
就我所知,格雷格的建议是不正确的。您应该始终使用CLR包装器属性中的
GetValue
/SetValue
<代码>设置当前值在需要属性接受给定值但不想覆盖已针对属性配置的任何绑定、触发器或样式的情况下更有用。关于接受的答案:
我发现这很好地解释了SetCurrentValue()。请注意,依赖项属性值优先系统将如何将局部值置于绑定值之上。这解释了评论者的意外行为。演示工具(完整):
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
讨论示例:
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
讨论:
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
dependencProperty
的初始状态,其DefaultValue
为'42',已断言BaseValueSource.Default
标志ReadLocalValue()
返回全局单例实例dependencProperty.UnsetValue
SetValue()
按预期在内部存储BaseValueSource.Local
值
SetValue
存储恰好等于DefaultValue
的值不会还原BaseValueSource.Default
状态(与下面的#6比较)
ClearValue()
。(见下文注释)
SetCurrentValue()
,通过强制生成属性值,而不断言BaseValueSource.Local
模式。请注意,以前的BaseValueSource
默认值仍然有效,尽管该属性现在报告的值不是,实际上等于其默认值
这意味着检查
GetValueSource()
返回的BaseValueSource
状态是否为BaseValueSource。Default
是not当前属性值是否等于DP metatdata的默认值的可靠指示器
SetCurrentValue
检查DP元数据的DefaultValue
是否相等,以便删减被认为是“不必要”的冗余值。这种急切的清理可能是为了缓解DP存储膨胀,但它也会使DP状态的透明度变得复杂,因为它有一种特殊的“取消屏蔽”行为,如果不完全理解,可能会导致模糊的错误。例如,#6将DP清除回与ClearValue()
无法区分的原始状态
BaseValueSource
是当前的
,而不是本地的
;将#5/#6与对#7进行比较,尽管报告的属性值相同,但内部状态标志差异很大
ClearValue()
:
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
很明显,任何SetValue()
操作都不会调用PropertyChangedCallback
,因为该操作最终不会导致对属性的上一个值的更改。这是最基本的,因为SetValue
隐含了一个假设,即正在进行的更改与工作中的活动属性的值有关。不那么直观的是,同样的逻辑也适用于ClearValue()
例如,在#4中,
ClearValue
导致本地值42
从内部DP存储中删除,以及其他内部状态更改,所有这些都是预期的。问题在于,在当前的ClearValue
调用过程中,是否调用OnPropertyChanged
取决于之前的值是否等于元数据默认值操作似乎意味着对先前状态的摘要丢弃(因此通常被认为是上下文任意的)ClearValue()
的行为依赖于某些/任何先前状态时,人们可能不会想到这种不一致性。特别是对于一个涉及(并混合)新州的重大行为,例如是否发出“变更”通知。@Meleak:老实说,我认为这篇文章有点不清楚。我想他是想说SetCurrentValue
应该用在你控制的任何地方