如果经历过
.NET
的
1.0,1.1
以及
2.0
版本,你就很可能发现
.NET 3.0
中的
WPF
区域中的一些文档有点不同。具体来说,
WPF
负责介绍几个
CLR
和托管代码封装方面的新概念。
WPF SDK
团队为在参考资料中展示这些新概念而做的努力是很大的进步,主要致力于改变,因为其它的技术也在它们的
API
中采用了相同或者类似的范例。
System.Reflection
和
.NET 3.0 SDK
微软用于创建托管
SDK
框架的
“
魔法
”
其实就是映射进程(典型的就是采用托管映射,但有时也有非托管的映射,这取决于
API
)。编译工具映射所有
.NET 3.0
的
API
,
SDK
作者就在纲要中填充映射告诉我们的关于
API
的消息(至少这是一个目标)。但是对于比
System.Reflection
本身更新
的编程概念的映射,
System.Reflection
做得不是特别好。你可以通过查看定制特性来得到一些更具体的信息。但对于那些像
XAML
一样的语
言,或者独立属性,由于
System.Reflectio
从
1.1
开始就没有本质的改变,所以不能为
3.0
提供好的
API
。如果你要编写自己的映射,你不
得不做些额外的创造工作(我不会在这里描述这个问题,因为太复杂了,而且超出了本主题的范围)。对我们的
SDK
开发团队来说,他们也不得不非常熟悉映射代
码。然后,其他的各种各样的人,包括一些像我们这样的程序员不得不跟上表示策略
——
怎么在更好,更标准的托管代码段文档中表示额外的信息,比如异常和返回
值等。
0000
正在讨论的隐藏的秘密是参考主题部分,这部分是大量的设计会议和开发工作的结果。每一个隐藏秘密都代表着编程的一个具体方面,和
WPF
非常相关并且对
WPF
来说是新内容。所有的信息都在
SDK
页面,等待你的发掘。但是,我们还没搞清楚这些突然在
WPF
参考文档中出现的额外段落是什么,以及他们意味着什
么。
抛开这些吧。让我们来照亮这些
WPF
文档中隐藏的秘密。一切都会得到解释!
独立属性
很多时候会被问道一个问题
“
独立属性到底是什么?
”
或者一个相关的更尖锐的问题
“
我为什么要去关心一个东西是不是独立属性呢?
”
我们的答案是:独立属性总览。
跨过这个概念上的障碍之后,下一个逻辑上的问题可能是
“
好吧,独立属性就是一种支持
CLR
属性的方式,那我该怎么分别那些属性是通过这种方式被支持的呢?
”
我们遇到的第一个隐藏秘密是:独立属性,和独立属性信息段。
在文档中提到两种方法来判断某个给定的属性是否是独立属性:
1
)当你在浏览任何类型的成员表,并且看到公共属性,读描述的时候。如果这个属性是独立属性,那么描述的最后一句就是
“
这是一个独立特性。
”
2
)假设你在说明
CLR
属性的
SDK
的主题页面。同样,在成员表的相同的描述中,你可以找到这句话
“
这是一个独立属性
”
。除了描述外,每一个独立属性的属性页面内还有一段可以被合适地成为独立属性信息段。这一段在表格中包含两点:
一个到含有独立属性标志符的域的链接。很多属性系统
API
函数都需要这个标志符以执行一个属性或者获得关于它的信息。有人说,对那些只是获取或设置某个已
经存在的具体属性的应用程序编程来说,使用属性系统
API
并不总是必须的,因为你可以调用更简单的独立属性
CLR“
封装
”
。这样,标志符主要是和包含独立
属性的高级编程任务相关,比如处理属性元数据,或者追踪属性值。
如果一个属性是框架层的属性,那么独立属性信息段会把元数据中
“
标记
”
为
true
的列出来。当独立属性被
WPF
框架层解释时,标记报告独立属性的某些共同
特征,尤其是子特征,比如,整体系统,数据绑定,或属性值继承。
SDK
报告这些标记,因为这有助于实例了解改变属性是否会强迫修改整体设计,或是否你可以
省略指定绑定的两个状态,因为这是独立属性的默认设置。
默认值
横跨独立属性和
“
常规
”
属性的一个概念是默认值。一般来说,
.NET
文档会在属性值段告诉你属性的默认值,并且为保持一致性,这也是默认属性被报告给独立
属性的地方。但是,独立属性默认值实际上来自属性元数据,尽管在一个平面上
CLR
属性可能来自一个类或者是拓展执行。这样,通过重写属性元数据,独立属性
就可以被子类或新的属性拥有者轻易改变。在已有的
WPF
独立属性中偶尔会发生这种情况。当发生时,每一个类的重写都会被记录在
Remark
段。
Routed
事件
在你不可避免地问
“
什么是
routed
事件?
”
之前,可以去这里看看
Routed Events Overview
。现在我们解决这个问题了。
不
像独立属性,
routed
事件没有像
“
这是一个
routed
事件
”
之类的习惯性描述。基本元素(
UIElement,
FrameworkElement, ContentElement, FrameworkContentElement
)有很多的
routed
事件:可能它们的事件有
75%
都是
routed
的。其它的类,像控件也会有少数的
routed
事件,也许和着一些不
route
的标准
CLR
事件。为了区分一个事件是否
route
,你需要在事件主题看看是否有
Routed
事件信息段。
Routed
事件信息段是一个有如下三项的表:
*
一个指向包含有
routed
事件标志符的域的链接。和属性系统
API
以及独立属性标志符一样,事件系统
API
也需要这个标志符以接入事件。像增加或移除句柄一类的简单操作并不是必须
标志符,这也是因为
routed
事件会有一个
“
包装
”
,这样就可以支持
CLR
语言中增加
/
移除事件句柄的
CLR
语法。但,如果直接使用
AddHandler
或调用
RaiseEvent
,就需要知道
routed
事件的标志符。
*Routing
策略。有三种可能:
Bubbling
,
Tunneling
,和
Direct
。这儿有个小秘密:如果之前查看过事件名字,那么
routing
策略就总是
Tunneling
,这是一个惯例。但区分
Bubbling
和
Direct
就有点困难了,因为没有不同的命名习惯。所以,我们提
供了参照页的信息。
Direct
事件实际上没有在它的元素之外
route
,但他们仍然服务于
WPF-specific
目的,在这里有描述
Routed Events Overview
。
* Delegate
类型。你可以在声明事件的语法中找到列出的
delegate
。我们在这里重复是为了方便,所以你可以直接跳到
“
写恰当的句柄
”
的地方。
附带属性
严格地说,附带属性是
XAML
的概念,而不是
WPF
的。但
WPF
是第一个发行的采用了
XAML
语言的工具。所以
WPF
是用文档来描述
XAML
语法和
XAML
语言的先锋。如果你是代码编写员,并看了某个附带属性的叫做
DockPanel.Dock
的文档,就会注意到一些特别的东西:没有
XAML
语法,没有代码语法。如果浏览
DockPanel
类,去看映射或对象就可以
证实:对
CLR
没有类似于
“Dock”
属性的东西。甚至为了在其它的产生映射的参照中使这个页面存在,
SDK
开发团队不得不注入这个页面。然而,对我们这
些在标记和代码间可以随意转换的人来说,附带属性的语法段确实提供了一个到附带属性的
“
真实
”
代码
API
的链接,这可以成为一系列获取和设置的接入方法。
对
DockPanel
类来说有
GetDock
和
SetDock
。(不幸的是,在
MSDN
版本的这些页面中似乎没有这些链接;在
Visual Studio
和
offline Windows SDKs
中有
…
相信我
...
)
附属事件
类似地,这是一个
XAML
的概念,但在
WPF
得到具体的应用。
XAML
语法,但对同等代码接入来说是一个
“
秘密
”
接入方法。在附属事件情况下,这些方法的
类型是
Add*Handler
和
Remove*Handler
。例如,
Mouse.MouseDown
调用
AddMouseDownHandler
就可以
有附带到给定的
UIElement
实例的句柄,并可以通过
RemoveMouseDownHandler
移除。对实际应用来说,附属事件不一定那么重要,
因为大多数都是被
UIElement
以更方便的方式重新使用而已。但如果你在写一套相关的控件,或者在实现一个服务,那么附属事件就很可能进入你的视野。
XAML
语法
SDK
文档提供了
XAML
各种用途下的
XAML
语法,比如用来实例化一个
XAML
类的对象元素标签,用来设置属性或附带事件句柄的属性,还有
XAML
的具
体概念,如
content property
或
property element
语法。另一个隐藏的秘密来了
...
好的,也不是那么的隐秘了,因为我以前已经在博客上写过了。
XAML
不一定非要被绑定到计划中。最终决定
XAML
是否有效的是
XAML loader
,最终成功还是失败取决于一些加载动作,比如试图在组件中找到一个命名匹配的类型,调用它的默认
ctor
,以及返回一个实例。或者,一旦对象
存在,就是试图找到一个匹配属性名字的
property
,然后试图用属性值的
string-to-X
变换,或者甚至是更复杂的在
property
元素中以
子关系存在的
XAML
的什么东西的封装来填充它。对于保持
XAML
的扩展性来说是有必要的,但是这会让编写文档和静态的
XAML
词典更困难一点儿。其一,
parser
会允许你实例化一个在对象模块中没有
“
家
”
的元素。比如,大多数
EventArgs
子类可以在
XAML
中建立,因为它们可以方便的拥有一个默
认
ctor
(加入
XAML
俱乐部是如此容易
....
)但是,然后呢?从狭义来说,
XAML
是
UI
定义上的。广义上讲,
XAML
是相关的对象和你希望建立的
他们的属性的任何结构的定义。你不能把
EventArgs
作为任何具有可疑资源收集异常的东西的子元素。这让
XAML
文档进退两难:这是
XAML
吗,或者
不是?这个困惑经常出现。一般来说,我们用具体情况来说明
XAML
。有什么原因让你希望用
XAML
来实例化这个类吗?如果有,我们会给你看一个语法。如果
没有,就像
3.0
的
EventArgs
子类一样,我们会告诉你这并不是一个典型的应用,虽然
XAML loader
会在和其它面向应用的对象模型完全隔离的情况下用
XAML
来建立一个。
另一个秘密:虽然没有写出语法(会说这是不适用的东西),但是在
frameworks
中有很多支持
XAML
的类。一般来说,这是因为这些类来自更早的版
本,可以在整个
3.0 framework
中使用,因为可能合法的
XAML
使用率会很大。所以,为了填补空白,用户需要知道一些
XAML
的技巧。对初学者,读
XAML and Custom
Classes
就可以了。当以默认的
ctor
和一些其它的限定来符合
XAML
加载器的要求时,定制的类和已有的类没什么不同的。也去看看
x:Array
Markup Extension
中的例子吧。这个例子讲了系统名字空间和
mscorlib
组件,这样你就可以吧
String
类作为一个直接对象进行实例化。你可以外推
这些简单的概念,并做些更有用的事情。甚至设想这个场景都有点困难,但是你们是一个充满创造性的集体:让我们看看你们能做什么!描绘一些
System.Data
的结构?谁知道在
pre-3.0
.NET
的核心部分用了多少
XAML
?
没有
XAML
属性列表?
SDK
并不是真的有一个
“
所有权页面
”
,这是
XAML
特有的。你可以把
property
列表看作是普通的成员表的一部分,但要选出
XAML
属性有点困难,
因为有些是只读的,有些又不使用支持
XAML
的类型,等等。这里,我想我们不得不承认工具和设计者可以比只利用
SDK
的成员表做得更好。因为工具和设计者
有语义的优势;他们知道你刚刚实例化了什么面板子类,在元素树里面它处于什么位置等。好好地综合基于工具的只列出基本的可能性的智能,然后学会按
F1
来获
取
SDK
页面的更多的帮助信息。这是我们追赶即将来临的工具
/SDK
的发行的下一步。限于篇幅,不能细细讲解。
没有
XAML XSD
的计划?
我以前在博客上写过这个。对一个像
WPF
这样有很多维的产品来说,
XAML
的计划很困难。但你也许已经注意到接下来的
XAML
综合技术(
Workflow Foundation,
Silverlight
)确实包括了
XSD
类型的计划。说到
WPF XAML
的计划,我们仍然保持观望。
看了一遍,感觉太浮云了