闽公网安备 35020302035485号
public class ValidationParams:DependencyObject
{
public object Param1
{
get { return (object)GetValue(Param1Property); }
set { SetValue(Param1Property, value); }
}
// 堆代码 duidaima.com
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty Param1Property =
DependencyProperty.Register("Param1", typeof(object), typeof(ValidationParams), new PropertyMetadata(null));
}
代码中Param1Property才是真正的依赖属性,Param1是依赖属性的包装器,这里有一个命名约定,依赖属性的名称是对应包装器名称+Property组成。在Visual studio中输入propdp,然后Tab键就会自动生成依赖属性以及包装器的代码片段,然后根据实际情况修改相应的参数和类型。从修饰符可以看出依赖属性是一个静态的只读变量,要确保不同实例的依赖属性正确赋值,肯定不能把数据直接保存到这个静态变量中。这里其实也是依赖属性机制的核心。
DependencyProperty:依赖属性实例都是单例,其中DefaultMetadata存储了依赖属性的默认值,提供变化通知、限制、检验等回调以及子类override依赖属性的渠道。GlobalIndex用于检索DependencyProperty的实例。应用程序中注册的所有DependencyProperty的实例都存放于名为PropertyFromName的Hashtable中。
DependencyObject:依赖属性的宿主对象,_effectiveValues是一个私有的有序数组,用来存储本对象实例中修改过值得依赖属性,GetValue、SetValue方法用于读写依赖属性的数值。

private static DependencyProperty RegisterCommon(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
{
FromNameKey key = new FromNameKey(name, ownerType);
.....略去校验以及默认元数据代码
// Create property
DependencyProperty dp = new DependencyProperty(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
// Map owner type to this property
// Build key
lock (Synchronized)
{
PropertyFromName[key] = dp;
}
return dp;
}
代码的大致意思是生成一个FromNameKey类型的key,然后构造一个DependencyProperty实例dp,并存放到名为PropertyFromName的Hashtable中,最后返回这个实例dp。
FromNameKey是DependencyProperty中的内部私有类,其代码如下:
private class FromNameKey
{
public FromNameKey(string name, Type ownerType)
{
_name = name;
_ownerType = ownerType;
_hashCode = _name.GetHashCode() ^ _ownerType.GetHashCode();
}
public override int GetHashCode()
{
return _hashCode;
}
...略去部分代码
private string _name;
private Type _ownerType;
private int _hashCode;
}
这里特地介绍这个类是因为FromNameKey对象是依赖属性实例的key,它的hashcode是由Register的第一个参数(依赖属性包装器属性名称字符串)的hashcode和第三个参数(依赖属性宿主类型)的hashcode做异或运算得来的,这样设计确保了每个DependecyObject类型中不同名称的依赖属性的实例是唯一的。public object GetValue(DependencyProperty dp)
{
// Do not allow foreign threads access.
// (This is a noop if this object is not assigned to a Dispatcher.)
//
this.VerifyAccess();
ArgumentNullException.ThrowIfNull(dp);
// Call Forwarded
return GetValueEntry(
LookupEntry(dp.GlobalIndex),
dp,
null,
RequestFlags.FullyResolved).Value;
}
方法前几行是线程安全性和参数有效性检测,最后一行是获取依赖属性的值。LookupEntry是根据DependencyProperty实例的GlobalIndex在_effectiveValues数组中查找依赖属性的有效值EffectiveValueEntry,找到后返回其索引对象EntryIndex。EntryIndex主要包含Index和Found两个属性,Index表示查找到的索引值,Found表示是否找到目标元素。前边提到依赖属性支持多属性值,WPF中可以通过多种方法为一个依赖项属性赋值,如通过样式、模板、触发器、动画等为依赖项属性赋值的同时,控件本身的声明也为属性进行了赋值。在这种情况下,WPF只能选择其中的一种赋值作为该属性的取值,这就涉及到取值的优先级问题。
从上一小节的图中可以看到EffectiveValueEntry中有两个属性:ModifiedValue和BaseValueSourceInternal,ModifiedValue用于跟踪依赖属性的值是否被修改以及被修改的状态。BaseValueSourceInternal是一个枚举,它用于表示依赖属性的值是从哪里获取的。在与ModifiedValue一起使用,可以确定最终呈现的属性值。
internal EffectiveValueEntry GetFlattenedEntry(RequestFlags requests)
{
......略去部分代码
// Note that the modified values have an order of precedence
// 1. Coerced Value (including Current value)
// 2. Animated Value
// 3. Expression Value
// Also note that we support any arbitrary combinations of these
// modifiers and will yet the precedence metioned above.
if (IsCoerced)
{
......略去部分代码
}
else if (IsAnimated)
{
......略去部分代码
}
else
{
......略去部分代码
}
return entry;
}
其中表达式值包含样式、模板、触发器、主题、控件本身对属性赋值或者绑定表达式。其优先级则是在BaseValueSourceInternal中定义的。枚举元素排列顺序与取值优先级顺序刚好相反。// Note that these enum values are arranged in the reverse order of
// precendence for these sources. Local value has highest
// precedence and Default value has the least. Note that we do not
// store default values in the _effectiveValues cache unless it is
// being coerced/animated.
[FriendAccessAllowed] // Built into Base, also used by Core & Framework.
internal enum BaseValueSourceInternal : short
{
Unknown = 0,
Default = 1,
Inherited = 2,
ThemeStyle = 3,
ThemeStyleTrigger = 4,
Style = 5,
TemplateTrigger = 6,
StyleTrigger = 7,
ImplicitReference = 8,
ParentTemplate = 9,
ParentTemplateTrigger = 10,
Local = 11,
}
综合起来依赖属性取值优先级列表如下:依赖属性元数据中的默认值