(原创)3.2 AddOwner和OverrideMetadata的区别
1 AddOwner和OverrideMetadata
1.1 分析
从源代码上看,AddOwner函数中调用了OverrideMetadata, 并且把本类和依赖属性的哈希值加入到依赖属性的一张哈希列表private static Hashtable PropertyFromName中,哈希表的键值是用当前类类型的哈希值和依赖属性类类型的哈希值异或得到的,此表用来记录当前的依赖属性是属于哪个类的。
此哈希表很重要,因为在xaml解析器中,就是利用PropertyFromName表来分析依赖属性的。看到一片博客是这样说的,PropertyFromName hashtable is mainly use by the xaml => code process(翻译:PropertyFromName hashtable 主要用来从xaml到代码的转化的处理), which can be found by analyzing the DependencyProperty.FromName() method using reflector's "use by" fuction。
下边,我们主要介绍一下,OverrideMetadata函数是在干什么?查看源代码如下:
public DependencyProperty AddOwner(Type ownerType, PropertyMetadata typeMetadata)
{
if (ownerType == null)
{
throw new ArgumentNullException("ownerType");
}
FromNameKey key = new FromNameKey(this.Name, ownerType);//获取hashcode
lock (Synchronized)
{
if (PropertyFromName.Contains(key))
{
throw new ArgumentException(MS.Internal.WindowsBase.SR.Get("PropertyAlreadyRegistered", new object[] { this.Name, ownerType.Name }));
}
}
if (typeMetadata != null)
{
this.OverrideMetadata(ownerType, typeMetadata);//@1 进入OverrideMetaData
}
lock (Synchronized)
{
PropertyFromName.set_Item(key, this);//PropertyFromName hashtable
}
return this;
}
在OverrideMetadata中代码嵌套多,直接写出有用的代码
DependencyObjectType dType = DependencyObjectType.FromSystemType(forType);
PropertyMetadata baseMetadata = this.GetMetadata(dType.BaseType);//dType.BaseType表示继承体系中的父类;例如,AnimalButton类BaseType表示的Button;获取GetMetadata的规则,可以查看《附加属性原理》的1.1.1.1中的分析:大概就是如果本继承体系中没有,就直接选取_defaultMetadata作为元数据;
if (baseMetadata.PropertyChangedCallback != null)
{
Delegate[] invocationList = baseMetadata.PropertyChangedCallback.GetInvocationList();
if (invocationList.Length > 0)
{
System.Windows.PropertyChangedCallback a = (System.Windows.PropertyChangedCallback) invocationList[0];
for (int i = 1; i < invocationList.Length; i++)
{
a = (System.Windows.PropertyChangedCallback) Delegate.Combine(a, (System.Windows.PropertyChangedCallback) invocationList[i]);
}
a = (System.Windows.PropertyChangedCallback) Delegate.Combine(a, this._propertyChangedCallback);
this._propertyChangedCallback = a;
}
}//合并PropertyMetaChanged的事件响应
if (this._coerceValueCallback == null)
{
this._coerceValueCallback = baseMetadata.CoerceValueCallback;//直接覆盖,如果提供,什么都不做
}
if (this._freezeValueCallback == null)
{
this._freezeValueCallback = baseMetadata.FreezeValueCallback;
}
1.2 举例
我们可以得到这样的结论,AddOwner不是依赖属性或者附加属性的专利,OverrideMetadata也不是。其中,AddOwner是OverrideMetadata和添加PropertyFromName哈希表的合集,OverrideMetadata是把当前元数据和继承体系中最近的父类的依赖属性的元数据PropertyChangedCallback进行合并,CoerceCallback进行取舍。下边附上一例:
例子:
public class Feeling : DependencyObject
{
//注册Dependency Property
public static readonly DependencyProperty FeelProperty = DependencyProperty.Register("Feel",
typeof(string),
typeof(Feeling),
new PropertyMetadata("feel-happy", new PropertyChangedCallback(FeelChanged))); private static void FeelChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Trace.WriteLine("the feel is changed, new Value is " + e.NewValue.ToString());
} //注册Attached Property
public static readonly DependencyProperty SenseProperty = DependencyProperty.RegisterAttached("Sense",
typeof(string),
typeof(Feeling),
new PropertyMetadata("sense-happy", new PropertyChangedCallback(SenseChanged)));
private static void SenseChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Trace.WriteLine("the sense is changed, new value is " + e.NewValue.ToString());
//Window window = new Window();
//window.Title = sender.GetType().ToString();
//window.Show();
} public static string GetSense(DependencyObject dO)
{
return dO.GetValue(SenseProperty) as string;
} public static void SetSense(DependencyObject dO, string val)
{
dO.SetValue(SenseProperty, val);
}
} public class AnimalButton : Button
{
//在 dependency property addowner调用,propertyFromName[key] = this; //具体有什么用处
//key = ownerType ^ propertyname
//如果AddOwner了附加依赖属性,那么,
public static readonly DependencyProperty SenseProperty =
Feeling.SenseProperty.AddOwner(typeof(AnimalButton),
new PropertyMetadata("add owner animal button", new PropertyChangedCallback(AnimalButtonSensePropertyChanged)));
private static void AnimalButtonSensePropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Trace.WriteLine("AnimalButton SenseProperty changed, new value is " + e.NewValue.ToString());
} public string Sense
{
get
{
return GetValue(SenseProperty) as string;
}
set
{
SetValue(SenseProperty, value);
}
} private static void AnimalButtonFeelPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Trace.WriteLine("AnimalButton FeelProperty Changed, new value is " + e.NewValue.ToString());
}
public static readonly DependencyProperty FeelProperty = Feeling.FeelProperty.AddOwner(typeof(AnimalButton),
new PropertyMetadata(("add owner animal FeelProperty"), new PropertyChangedCallback(AnimalButtonFeelPropertyChanged)));
public string Feel
{
get
{
return GetValue(FeelProperty) as string;
}
set
{
SetValue(FeelProperty, value);
}
}
}
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" x:Name="textBox" FontSize="32"></TextBox>
<loc:AnimalButton Grid.Row="1"
Content="Button"
Click="AnimalButton_Click"
Feel="{Binding SenseString, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type loc:MainWindow}}}"
Sense="{Binding SenseString, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type loc:MainWindow}}}"/>
</Grid> </Window>
public partial class MainWindow : Window,INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
// DependencyObjectType dt = DependencyObjectType.FromSystemType(typeof(Window));
// DependencyObjectType dtt = DependencyObjectType.FromSystemType(typeof(AnimalButton));
// DependencyObjectType dType = DependencyObjectType.FromSystemType(typeof(AnimalButton));
// DependencyObjectType baseType = dType.BaseType;//获取当前依赖属性的父类中的对应的MetaData;
// PropertyMetadata baseMetadata = Feeling.SenseProperty.GetMetadata(baseType);
// int xx = 0;
} private string _senseString = "main window";
public string SenseString
{
get
{
return _senseString;
}
set
{
if (value != _senseString)
{
_senseString = value;
Notify("SenseString");
}
}
} public event PropertyChangedEventHandler PropertyChanged;
void Notify(string name)
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
} private void AnimalButton_Click(object sender, RoutedEventArgs e)
{
SenseString = textBox.Text;
}
}
将会打印出
AnimalButton FeelProperty Changed, new value is RenDawei - 说明如果是依赖属性,OverrideMetadata的时候,获取的_defaultMetadata没有PropertyChanged回调函数,而附加依赖属性是有的;
the sense is changed, new value is RenDawei
AnimalButton SenseProperty changed, new value is RenDawei
(原创)3.2 AddOwner和OverrideMetadata的区别的更多相关文章
- (原创)sklearn中 F1-micro 与 F1-macro区别和计算原理
最近在使用sklearn做分类时候,用到metrics中的评价函数,其中有一个非常重要的评价函数是F1值,(关于这个值的原理自行google或者百度) 在sklearn中的计算F1的函数为 f1_sc ...
- [原创] delphi KeyUp、KeyPress、Keydown区别和用法,如何不按键盘调用事件
KeyPress (Sender: TObject; var Key: Char); 当用户按下键盘上的字符键(字母,数字) 会触发该事件,功能键则不会(F1-F12,Ctrl,Alt,Shift ...
- TGL站长关于常见问题的回复
问题地址: http://www.thegrouplet.com/thread-112923-1-1.html 问题: 网站配有太多的模板是否影响网站加载速度 月光答复: wp不需要删除其他的模板,不 ...
- mysql,left join on
转自http://www.oschina.net/question/89964_65912 觉得很有帮助,用来学习. 即使你认为自己已对 MySQL 的 LEFT JOIN 理解深刻,但我敢打赌,这篇 ...
- synchronized和Lock的区别是什么?
原创2020-11-19 11:38:29011024区别:1.lock是一个接口,而synchronized是java的一个关键字.2.synchronized在发生异常时会自动释放占有的锁 ...
- 【原创】c++拷贝初始化和直接初始化的底层区别
说明:如果看不懂的童鞋,可以直接跳到最后看总结,再回头看上文内容,如有不对,请指出~ 环境:visual studio 2013(编译器优化关闭) 源代码 下面的源代码修改自http://blog.c ...
- 【原创】Java和C#下String类型中的==和equals的原理与区别
一.Java下 1.几个例子 public static void main(String[] arge) { String str1 = new String("1234"); ...
- js学习之函数声明与函数表达式区别[原创]
作为一名js初学者,与大家分享下.Javascript中有函数声明提升的功能,会优先编译函数声明部分.比如, ff(); function ff(){ alert("hello world. ...
- module.exports,exports,export和export default,import与require区别与联系【原创】
还在为module.exports.exports.export和export default,import和require区别与联系发愁吗,这一篇基本就够了! 一.首先搞清楚一个基本问题: modu ...
随机推荐
- Upgrading to Java 8——第三章 Optional and Similar Classes
Java程序员对付空指针异常已经好多年了.在Java8中将有新的方式去处理他们.通过包装一个潜在的可能为null的类称为Optianal. 在Java8中添加了the Optional, Option ...
- SPOJ 057 Supernumbers in a permutation
原题链接:http://www.spoj.com/problems/SUPPER/ 这道题n<=200000,那么确定为nlogn的算法,再定位到求LIS的O(nlogn)的算法. 对于每个a[ ...
- 【BZOJ】【1010】【HNOI2008】玩具装箱Toy
DP/斜率优化 根据题目描述很容易列出动规方程:$$ f[i]=min\{ f[j]+(s[i]-s[j]+i-j-1-L)^2 \}$$ 其中 $$s[i]=\sum_{k=1}^{i} c[k] ...
- 【BZOJ】【1034】【ZJOI2008】泡泡堂BNB
贪心 类似田忌赛马策略的一个贪心= = 随便YY了一个做法居然A了…… 简单来说就是先强对强,弱对弱,能赢就赢,不能赢就让弱的那个去对强的那个,剩下的人继续依次捉对比赛(继续刚刚的策略),现在人数还是 ...
- angularJs 问题
1. IE不能渲染指令中的 style="background-color",而chrome和firefox可以 <!DOCTYPE html> <html ng ...
- 12 高性能I/O框架库Libevent
这里不讲Libevent库的具体内容了,从宏观上对I/O库整体做个介绍 Linux服务器程序必须处理三类事件:I/O事件,信号和定时事件 统一事件源:统一处理这三类事件既能使代码简单易懂,又能避免一些 ...
- POC
大概就是原型验证的意思 验证概念 编辑 概念验证(Proof of concept,简称POC)是对某些想法的一个不完整的实现,以证明其可行性,示范其原理,其目的是为了验证一些概念或理论.在计算机安全 ...
- FM算法
1.FM背景 在计算广告中,CTR预估(click-through rate)是非常重要的一个环节,因为DSP后面的出价要依赖于CTR预估的结果.在前面的相关博文中,我们已经提到了CTR中相关特征工程 ...
- Runtime的用法
public class RuntimeTest { public static void main(String[] args) { Runtime run =Runtime.getRuntime( ...
- SPOJ375 Query on a tree(LCT边权)
之前做了两道点权的LCT,这次做一下边权的LCT.上网找了一下资料,发现对于边权的LCT有这么两种处理方法,一种是每条边建一个点,于是边权就转成点权了.另外一种则是每个边权对应到点权上,也就是每个点对 ...