学习silverlight没什么门路,跑了几趟书店都没买到sl的书,真慢。今天装了vs2008,于是打开vs的对象浏览器,看看sl里面的类库都是什么德行。
那么先从xaml文档的根节点元素开始看吧~~~ 查看之下还真是看不出什么所以然~~~
就这个图能看出什么端倪?所以说要搞清楚一个类库还是得先从她的身家背景开始看起...
Canvas的一家
据说谁的祖先都是从单细胞(object)发展而来的,那么从第二代开始看....
二代目:
System.Windows.DependencyObject “依赖对象” 一个抽象类,好像没什么好看的。
FindName是通过姓名找孩子(说也奇怪,到DependencyObject还没有Children这个属性,也没有WPF中独生子女的Content属性,这是干什么用的?找谁家的孩子?),下面的Name是自己本身的名字……其它的,看不懂……先放着……
第三代:
System.Windows.Media.Visual “可视对象” 也是抽象类
增加了2个方法,捕捉"鼠标事件"和释放"鼠标事件"
由于子元素存在于父元素“体内”,点击子元素实际上也应该“通知”父元素,所以鼠标事件是会向上传递的。
但是用户点击父元素的任意一部分,父元素怎么知道到底有没有点到什么子元素啊?总之,就是为了弄清楚咯吱哪里该谁笑的疑惑,就弄了这两个方法。总的来看,可能为了兼容1.0吧,封装的好差的说。本来应该由事件参数做的事情变成sender做了,不过从行为来看,这样也合理了,总之就是不同于.net winform。
讲个故事吧,爸爸和儿子守着一条小道,儿子在前。前面跑来一只兔子(或者是一只很身手很差的老鼠),那么如果儿子捕获了兔子(儿子很厉害,想捉一定会捉住,也就是执行CaptureMouse()返回true),那么父亲那里执行CaptureMouse()肯定会返回false了,除非儿子那里抓了又放了,就是ReleaseMouseCapture()了。
情况如同下面的代码:(txt是一个TextBlock)
{
public void Page_Loaded( object o, EventArgs e)
{
InitializeComponent();
this .MouseLeftButtonDown += new MouseEventHandler(Page_MouseLeftButtonDown);
txt.MouseLeftButtonDown += new MouseEventHandler(TextBlock_MouseLeftButtonDown);
}
void Page_MouseLeftButtonDown( object sender, MouseEventArgs e)
{
txt.Text += (sender as Visual).CaptureMouse().ToString();
// 如果点击了TextBlock,结果会是false,因为在TextBlock那已经执行了CaptureMouse()
// 如果点击了Canvas的其他部分(如空白部分),结果会是true,因为变成是第一手处理了
}
void TextBlock_MouseLeftButtonDown( object sender, MouseEventArgs e)
{
txt.Text += (sender as Visual).CaptureMouse().ToString(); // 因为是第一个执行,会是true
// (sender as Visual).ReleaseMouseCapture();如果这句被执行了(放开兔子),那么Canvas那里就会是true了
}
}
第四代了:
System.Windows.UIElement “用户对象” 还是抽象类 增加一堆事件和属性、依赖属性。
很多很复杂……
第五代了:
System.Windows.FrameworkElement “框架元素” 抽象的
增加了重要的“父元素”属性 以及外观属性:高 和 宽
六代:
子承父业,到了System.Windows.Controls.Panel,长成了容器级的元素
Children属性管理子元素,它是一个MS.Internal.Collection<Visual>类型的子类
最后到了Canvas 在Penel的基础上增加了2个依赖属性
现在没得逃避了。
所谓依赖属性,就是通过被依赖的对象起作用,就如一个TextBlock对象是Canvas对象的子对象,那么Canvas对象就通过Canvas.Left对TextBlock起管理的作用,但离开了Canvas,这个属性也就没有作用了。就好像“母亲”拥有的“母爱”依赖于“孩子的存在”而存在,当孩子离开了母亲,这种“爱”也就无从谈起了。
依赖关系,也就是WPF中“视觉元素”相互依赖的奥义了。而所有的依赖属性,都是父元素与子元素之前牵扯不断的关系,而这些属性都是为“视觉体现”而服务的。
(以上是我自己的解释)
而依赖对象是怎么工作的呢?其实打字到这一行之前我也不清楚,只是以前看过一篇WPF的关于依赖属性的文章,留下一点模糊的记忆,然后刚才回去又仔细查阅了对象信息,发现原来DependencyObject类的两个重要方法有玄机:
其实就是DependencyObject里面有一个隐藏的“字典”对象,通过父元素调用的,比如Canvas调用了TextBlock的SetValue方法
this.FindName("aTextBlock").SetValue(Canvas.LeftProperty,20);
相当于,父对象把一个值(这里是20)存进了子对象的“字典”里,而父亲的(静态只读成员)LeftProperty就是那把钥匙,也就是Key!!!!哈哈哈 ,终于理解了。那把钥匙可以打开所有子对象的“字典”,取出匹配于LeftProperty的值。
double left = (double )child.GetValue(Canvas.LeftProperty);
//....
}
这也就是为什么脚本可以这么写<TextBlock Canvas.Left="20">,而TextBlock类却没有一个Canvas.Top属性的原因了,而xaml中声明式的指定Canvas.Left,是由xaml解析引擎的时候自动完成的。
this.FindName("aTextBlock").SetValue(Canvas.LeftProperty,20);
了解了依赖属性的工作方式后,很容易通过这个特点来使用xaml标记用户自定义控件……
就这样了。。。
续:
经过继续研究,发现所谓“依赖属性”的作用实在“博大”,它可以使用于本对象以外的"包装类"对其包装,如xaml解析对象通过调用SetValue对UI对象进行初始化;渲染引擎使用GetValue取得它与父元素相依赖的属性值(如在渲染Canvas的子对象时需要子元素中Canvas.Top属性的值)
“依赖属性集”既可以放本身需要的属性,也可以放其他元素的所需要的信息集。以“键”和“值”的方式存取。。。。很方便,很强大!