十五. 模拟依赖属性实现
古人有”不入虎穴焉得虎子“的名句,我们今天也试着入一入虎穴,探探依赖属性里面到底藏着什么不可告人的秘密,在往下讲之前,我们先来看一下DependencyObject 、DependencyProperty 以及PropertyMetadata到底包含哪些功能,如下面三幅图



通过前面三幅图,我们就可以了解WPF依赖属性系统的大体结构以及主要功能,再者通过前面我们对它的使用,对它的内部实现也有一个相对比较清晰 的认识,那么接下来要做的就是:借助Reflector+VS调试内部代码功能一起来研究其内部的实现原理。 本来想详细写清楚开发的过程,但是有点多,所以我打算直接讲这几个类。大家也可以通过这个思路来试一试,同时还可以参考Mono的源码、WF的依赖属性源 码等。这里要推荐的是周永恒的博客,此人对技术的理解很是透彻,博文虽少,但每篇都堪称经典,所以他的文章,我都通读三遍。虽然大多概念都懂,并且读到深 处也能产生共鸣,其最主要目的还是学习他这种”阐述问题的思路“,后来也和此人MSN聊过几次。所以这个依赖属性的框架在某些程度上也借鉴了他的一些写 法。
有了前面的思路,首先定义DependencyProperty这个类,它里面存储前面我们提到希望抽出来的字段。DependencyProperty内部维护了一个全局的Map用来储存所有的DependencyProperty,对外暴露了一个Register方法用来注册新的DependencyProperty。当然,为了保证在Map中键值唯一,注册时需要根据传入的名字和注册类的的 HashCode取异或来生成Key。 所以我们就可以完成DependencyProperty类了,代码如下,介绍详见代码注释。:
public sealed class DependencyProperty {
//全局的IDictionary用来储存所有的DependencyProperty internal static IDictionary<int,DependencyProperty> properties = new Dictionary<int,175);">DependencyProperty>();
//存储元数据的集合 private List<PropertyMetadata> _metadataMap = new PropertyMetadata>();
private static int globalIndex = 0;
private PropertyMetadata def_metadata;
private bool attached;
private string name;
private int _index;
private Type owner_type;
private Type property_type;
private Type validator_type;
// 构造函数 private DependencyProperty()
{
}
//构造函数私有,保证外界不会对它进行实例化 private DependencyProperty(string name,175);">Type propertyType,175);">Type ownerType,175);">PropertyMetadata defaultMetadata)
{
this.name = name;
property_type = propertyType;
owner_type = ownerType;
def_metadata = defaultMetadata;
}
// 常用属性 public PropertyMetadata DefaultMetadata
{
get { return def_metadata; }
}
public bool IsAttached
{
get { return attached; }
}
public int Index
{
get { return _index; }
set { _index = value; }
}
public string Name
{
get { return name; }
}
public Type OwnerType
{
get { return owner_type; }
}
public Type PropertyType
{
get { return property_type; }
}
public Type ValidatorType
{
get { return validator_type; }
}
public override int GetHashCode()
{
return name.GetHashCode() ^ owner_type.GetHashCode();
}
//注册依赖属性 public static DependencyProperty Register(string name,175);">Type ownerType)
{
return Register(name,propertyType,ownerType,new PropertyMetadata());
}
//注册的公用方法,把这个依赖属性加入到IDictionary的键值集合中,Key为name和owner_type的GetHashCode取异,Value就是我们注册的DependencyProperty public static PropertyMetadata defaultMetadata)
{
DependencyProperty property = new DependencyProperty(name,defaultMetadata);
globalIndex++;
property.Index = globalIndex;
if (properties.ContainsKey(property.GetHashCode()))
{
throw new InvalidOperationException("A property with the same name already exists");
}
//把刚实例化的DependencyProperty添加到这个全局的IDictionary种 properties.Add(property.GetHashCode(),property);
return property;
}
//注册只读依赖属性 public static DependencyProperty RegisterReadOnly(string name,175);">PropertyMetadata typeMetadata)
{
DependencyProperty property = Register(name,typeMetadata);
return property;
}
//注册附加依赖属性 public static DependencyProperty RegisterAttached(string name,175);">Type ownerType)
{
return RegisterAttached(name,175);">PropertyMetadata(),null);
}
public static PropertyMetadata defaultMetadata)
{
return RegisterAttached(name,defaultMetadata,175);">PropertyMetadata defaultMetadata,175);">Type validatorType)
{
true;
property.validator_type = validatorType;
return property;
}
//子类继承重写以及其他需要重写Metadata的时候使用 public void OverrideMetadata(Type forType,175);">PropertyMetadata metadata)
{
metadata.Type = forType;
_metadataMap.Add(metadata);
}
//获取元数据信息 public PropertyMetadata GetMetadata(Type type)
{
PropertyMetadata medatata = _metadataMap.FirstOrDefault((i) => i.Type == type) ??
_metadataMap.FirstOrDefault((i) => type.IsSubclassOf(i.Type));
if (medatata == null)
{
medatata = def_metadata;
}
return medatata;
}
}
有了DependencyProperty ,那么接下来就需要定义DependencyObject 来使用这个DependencyProperty 。首先使用DependencyProperty .Register方法注册了一个新的DependencyProperty ,然后提供了GetValue和SetValue两个方法来操作刚刚构造的DependencyProperty 。这个时候我们看到一个简单的依赖属性系统已初见端倪了,详见代码注释。
namespace Realize_DPs
{
public abstract class DependencyObject : IDisposable {
//添加一个List来记录修改信息 private EffectiveValueEntry> _effectiveValues = new EffectiveValueEntry>();
//属性包装器,通过它来访问依赖属性 public object GetValue(DependencyProperty dp)
{
//首先通过判断是否改动过,以此来决定是读元数据的默认值还是改动了的值 EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault((i) => i.PropertyIndex == dp.Index);
if (effectiveValue.PropertyIndex != 0)
{
return effectiveValue.Value;
}
else {
PropertyMetadata metadata;
metadata = DependencyProperty.properties[dp.GetHashCode()].DefaultMetadata;
return metadata.DefaultValue;
}
}
//属性包装器,通过它来设置依赖属性的值 public void SetValue(DependencyProperty dp,object value)
{
//首先通过判断是否改动过,以及改动过,则继续对改动过的元素赋值,否则对_effectiveValues增加元素 EffectiveValueEntry effectiveValue = _effectiveValues.FirstOrDefault((i) => i.PropertyIndex == dp.Index);
if (effectiveValue.PropertyIndex != 0)
{
effectiveValue.Value = value;
}
else {
effectiveValue = new EffectiveValueEntry() { PropertyIndex = dp.Index,Value = value };
_effectiveValues.Add(effectiveValue);
}
}
public void Dispose()
{
//暂时还没有处理 }
}
internal struct EffectiveValueEntry {
internal int PropertyIndex { get; set; }
internal object Value { get; set; }
}
}
(编辑:安卓应用网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|