首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

2.7  对象元素的子元素

XAML文件就像所有的XML文件一样,必须有一个单独的根对象元素。因此,不必感到惊讶,对象元素是可以支持子对象元素的(不只是支持属性元素,考虑XAML时,它们并不是子元素)。一个对象元素可以有3种类型的子元素:一个内容属性值,集合项,或者一个能够通过类型转换到它的父元素的值。

2.7.1  内容属性

大多数WPF类(通过定制特性)指定了一个属性,该属性可以被设置为XML元素中的任何内容。这个属性叫作内容属性,它确实是一个让XAML呈现变得更轻便简单的捷径。从某种意义上讲,这些内容属性有点像(通常会被误解为)Visual Basic中的默认属性。

Button的Content属性就是这样指定的,因此下面的Button:

可以被重写为:

还有更有用的方式——内容更加复杂的Button:

可以被重写为:

并不一定要把内容属性叫作Content,像ComboBox、ListBox和TabControl(也在System. Windows.Controls命名空间中)这样的类就使用Items属性作为内容属性。

2.7.2  集合项

XAML允许将项添加到支持索引的两种类型的集合中:List和Dictionary。

1.List

List是实现了System.Collections.IList接口的集合,如System.Collections.ArrayList和许多WPF定义的集合类都是List。例如,下面的XAML向ListBox添加了两个项,它的Items属性是实现了IList的ItemCollection类型:

上面的代码与下面的C#代码功能相同:

因为Items是ListBox的内容属性,你可以将XAML进一步简化:

在以上这些示例中,ListBox的Items属性会自动被初始化为一个空的集合对象,因此代码可以正常工作。如果集合属性一开始就是空的(且是可读写的,不像ListBox的只读Items属性),你应该把这些项包装进一个显式的元素中,来实例化这个集合。

2.Dictionary

System.Windows.ResourceDictionary是WPF中的一个常用的集合类型,在第8章中将详细讲解。它实现了System.Collections.IDictionary接口,因此能够支持在过程式代码中添加、移除和枚举键/值对,这与创建一个典型的散列表是一样的。在XAML中,你可以向一个实现了IDictionary的集合中添加键/值对。例如,下面的XAML添加了两个Color对象到一个Resource- Dictionary中。

这利用了经过特殊处理的XAML Key关键字(在次级XML命名空间中定义),从而允许为每个Color值添加一个键。(Color类型没有定义Key属性。)因此,这里的XAML与下面的C#代码是一样的:

注意,在带有x:Key的XAML中指定的值总是被作为字符串处理的,除非使用标记扩展,但不会尝试使用类型转换。

2.7.3  更多类型转换

普通文本经常被用作对象元素的子元素,例如下面的基于XAML的SolidColorBrush声明:

这与下面的代码等价:

尽管Color没有被指定为内容属性。在本例中,第一个XAML代码段之所以能工作,是因为有类型转换器存在,它会把字符串'White'(或者'white',或'#FFFFFF')转换为SolidColorBrush对象。

虽然类型转换器在实现XAML的可读性方面起了重大作用,但不足的是,它们让XAML变得更魔幻,从而更难理解XAML如何映射到.NET对象的实例。使用目前的知识,应该说你还无法声明一个抽象的XAML类元素,因为没有办法实例化它。由于System.Windows.Media.Brush是SolidColorBrush、GradientBrush和其他一些具体笔刷的抽象基类,故可以如下表示之前的XAML代码段:

 

这是因为Brush的类型转换器仍然将把它理解成一个SolidColorBrush。这可能是一个不寻常的特性,但是在XAML中支持原始类型表示能力很重要,详见提示栏。

XAML扩展部分

因为XAML是设计用来与.NET类型系统一起工作的,你可以在其中使用任何类型的.NET对象(甚至是COM对象,这还多亏了COM的互操作性),也可以使用自己定义的对象,无论这些对象是不是与用户界面有关。但是,对象必须以“友好声明”(declarative-friendly)的方式进行设计。例如,如果一个类没有默认的构造函数,也没有提供有用的实例属性,那么它在XAML中是无法直接使用的。设计WPF API有很多细节来适应XAML的声明模型,它超越了通常.NET的设计规范。

WPF 程序集都被加上了XmlnsDefinitionAttribute属性,这样可以将.NET命名空间映射为XAML文件中的XML命名空间,但是对于那些不是专门为XAML设计的程序集又该如何处理呢?不使用这个特性吗?它们的类型仍然可以使用,只需要使用一个特殊的指令作为XML命名空间就可以了。例如,下面有一些普通、陈旧的C#代码,使用了包含在mscorlib.dll中的.NET Framework API:

 

以上代码在XAML中表示为:

 

clr-namespace标记允许直接在XAML中放入一个.NET命名空间。仅当需要的类型不在相同的程序集(XAML编译后生成的)中时,最后的程序集规范才是必须的。一般使用程序集的简单名称(如mscorlib)。但你可以使用规范的呈现方式,它是由System.Reflection.Assembly.Load提供支持的(虽然不允许空格),该函数包含了额外的信息,如版本或公共密钥令牌。

这个例子有两个关键点强调了不仅与.NET类型系统进行整合,也要与.NET Framework基类库中的特定类型进行整合。

q 子元素可以使用标准的XAML x:Key语法添加到父Hashtable中,因为Hashtable和.NET     Framework中的其他集合类从1.0版本开始就实现了IDictionary接口。

q 之所以可以这么直接使用System.Int32,是因为类型转换器已经存在,且类型转换器是      支持将字符串转换为整型的。因为XAML支持的类型转换器都是派生自System.Component- Model.TypeConverter的类,这个类从.NET Framework 1.0开始就有了。这其实也是   Windows Forms使用的类型转换机制(例如,允许在Visual Studio的属性格中输入字符串,   并将它们转换为适当的类型)。

对象元素的子元素的XAML处理规则

你现在已经看过3种类型的对象元素的子元素了。为了避免混淆,当转换子元素时,任何一个有效的XAML解析器或者编译器必须遵循下面的规则:

(1) 如果该类型实现了IList接口,就为每个子元素调用IList.Add。

(2) 否则,如果该类型实现了IDictionary,就为每个子元素调用IDictionary.Add,在该值的键和元素中使用x:Key特性值。

(3) 否则,如果父元素支持内容属性(由System.Windows.Markup.ContentPropertyAttri- bute表示),而且子元素的类型与该内容属性是兼容的,就把子元素作为它的值。

(4) 否则,如果子对象是普通文本,且有类型转换器将子对象转换为父类型(没有在父元素上设置属性),则把子元素作为类型转换器的输入,将输出作为父对象的实例。

(5) 其他情况下,则抛出一个错误。

规则1和规则2实现了之前的2.7.2节中描述的行为,规则3实现了2.7.1节中描述的行为,规则4解释了2.5节中提到的经常混淆的行为。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论