<b>什么是</b><b> XAML</b><b>?</b>
XAML 是一种声明性标记语言。如同应用于 .NET Framework 编程模型一样,XAML 简化了为 .NET Framework 应用程序创建 UI 的过程。您可以在声明性 XAML 标记中创建可见的 UI 元素,然后使用代码隐藏文件(通过分部类定义与标记相连接)将 UI 定义与运行时逻辑相分离。XAML 直接以程序集中定义的一组特定后备类型表示对象的实例化。
下面的示例演示如何创建作为 UI 一部分的按钮。此示例的目的仅在于供您初步了解 XAML 是如何表示常用 UI 编程形式的(它不是一个完整的示例)。
<StackPanel>
<Button Content="Click Me"/>
</StackPanel>
<b>XAML </b><b>语</b><b>法概述</b>
<b>XAML </b><b>对</b><b>象元素</b>
此示例指定了两个对象元素:<StackPanel>(含有内容,后面有一个结束标记)和 <Button .../>(自结束形式,包含几个特性)。对象元素 StackPanel 和 Button 各映射到一个类名,这些类由 WPF 定义并且是 WPF 程序集的一部分。指定对象元素标记时会创建一条 XAML 处理指令来创建一个新实例。每个实例都是在分析和加载 XAML 时通过调用基础类型的默认构造函数来创建的。
<b>特性</b><b>语</b><b>法(属性)</b>
对象的属性通常可表示为对象元素的特性。特性语法命名在特性语法中设置的属性,后跟赋值运算符 (=)。特性的值始终以包含在引号中的字符串的形式进行指定。
特性语法是最简单有效的属性设置语法,并且对于曾使用过标记语言的开发人员而言在使用中是最直观的语法。例如,以下标记将创建一个具有红色文本和蓝色背景的按钮,还将创建指定为 Content 的显示文本。
<Button Background="Blue" Foreground="Red" Content="This is a button"/>
<b>属性元素</b><b>语</b><b>法</b>
对于对象元素的某些属性,特性语法是不可能实现的,因为无法在特性语法的引号和字符串限制内充分地表达提供属性值所必需的对象或信息。对于这些情况,可以使用另一个语法,即属性元素语法。
属性元素开始标记的语法为 <类型名称.属性名称>。通常,该标记的内容是类型的一个对象元素,属性会将该元素作为其值。指定内容之后,必须用一个结束标记结束属性元素。结束标记的语法为 </类型名称.属性名称>。
如果可以使用特性语法,那么使用特性语法通常更为方便,且能够实现更为精简的标记,但这通常只是一个风格的问题,而不属于技术限制。下面的示例演示了在前面的特性语法示例中设置的相同属性,但这次对 Button 的所有属性使用了属性元素语法。
<Button>
<Button.Background>
<SolidColorBrush Color="Blue"/>
</Button.Background>
<Button.Foreground>
<SolidColorBrush Color="Red"/>
</Button.Foreground>
<Button.Content>
This is a button
</Button.Content>
</Button>
<b>集合</b><b>语</b><b>法</b>
XAML 语言包含一些优化,可以生成可读性更好的标记。其中的一项优化是:如果某个特定属性采用集合类型,则您在标记中声明为该属性的值内的子元素的项将成为集合的一部分。在这种情况下,子对象元素的集合是设置为集合属性的值。
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<!-- no explicit new GradientStopCollection, parser knows how to find or create -->
<GradientStop Offset="0.0" Color="Red" />
<GradientStop Offset="1.0" Color="Blue" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<b>XAML </b><b>内容属性</b>
XAML 指定了一个语言功能,通过该功能,一个类可以指定它的一个且仅一个属性为 XAML 内容属性。该对象元素的子元素用于设置该内容属性的值。换言之,仅对内容属性而言,您可以在 XAML 标记中设置该属性时省略属性元素,并在标记中生成更直观的父级/子级形式。
<Border>
<TextBox Width="300"/>
</Border>
<!--explicit equivalent-->
<Border.Child>
</Border.Child>
作为 XAML 语言的规则,XAML 内容属性的值必须完全在该对象元素的其他任何属性元素之前或之后指定。例如,下面的标记无法进行编译:
<a>复制</a>
<Button>I am a
<Button.Background>Blue</Button.Background>
blue button</Button>
<b>文本内容</b>
有少量 XAML 元素可直接将文本作为其内容来处理。若要实现此功能,必须满足以下条件之一:
类型必须声明一个类型转换器,该类型转换器将文本内容用作其初始化文本。例如,<Brush>Blue</Brush>。这种情况实际上并不常见。
类型必须为已知的 XAML 语言基元。
<b>内容属性和集合</b><b>语</b><b>法</b><b>组</b><b>合</b>
请看以下示例:
<Button>First Button</Button>
<Button>Second Button</Button>
<StackPanel.Children>
<!--<UIElementCollection>-->
<!--</UIElementCollection>-->
</StackPanel.Children>
<b>特性</b><b>语</b><b>法(事件)</b>
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExampleNamespace.ExamplePage">
<Button Click="Button_Click" >Click Me!</Button>
</Page>
<b>XAML </b><b>中的大小写和空白</b>
WPF XAML 处理器和序列化程序将忽略或删除所有无意义的空白,并规范化任何有意义的空白。这与 XAML 规范的默认空白行为建议一致。通常,只有当您在 XAML 内容属性中指定字符串时,此行为的重要性才会体现出来。简言之,XAML 将空格、换行符和制表符转化为空格,如果它们出现在一个连续字符串的任一端,则保留一个空格。有关 XAML 空白处理的完整说明不属于本主题的讨论范围。
<b>标记扩</b><b>展</b>
标记扩展是一个 XAML 语言概念。当用于提供特性语法的值时,大括号({ 和 })表示标记扩展用法。此用法指示 XAML 处理系统不要像通常那样将特性值视为一个文本字符串或者可转换为字符串的值。
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>
...
</Page.Resources>
<Border Style="{StaticResource PageBackground}">
<b>类</b><b>型</b><b>转换</b><b>器</b>
<Button Margin="10,20,10,30" Content="Click me"/>
<Button Content="Click me">
<Button.Margin>
<Thickness Left="10" Top="20" Right="10" Bottom="30"/>
</Button.Margin>
<b>说</b><b>明</b>
<b>XAML </b><b>根元素和</b><b> XAML </b><b>命名空</b><b>间</b>
根元素还包含特性 xmlns 和 xmlns:x。这些特性向 XAML 处理器指明哪些 XAML 命名空间包含标记将要作为元素引用的后备类型的类型定义。xmlns 特性明确指示默认的 XAML 命名空间。在默认的 XAML 命名空间中,可以不使用前缀指定标记中的对象元素。对于大多数 WPF 应用程序方案以及 SDK 的 WPF 部分中给出的几乎所有示例,默认的 XAML 命名空间均映射到为 WPF 命名空间 http://schemas.microsoft.com/winfx/2006/xaml/presentation。xmlns:x 特性指示另外一个 XAML 命名空间,该命名空间映射 XAML 语言命名空间 http://schemas.microsoft.com/winfx/2006/xaml。
使用 xmlns 定义用法范围和名称范围映射的做法符合 XML 1.0 规范。XAML 名称范围与 XML 名称范围的不同仅在于:XAML 名称范围还包含有关进行类型解析和分析 XAML 时名称范围的元素如何受类型支持的信息。
请注���,只有在每个 XAML 文件的根元素上,xmlns 特性才是绝对必需的。xmlns 定义将适用于根元素的所有子代元素(此行为也符合 xmlns 的 XML 1.0 规范。)同时允许根以下的其他元素上具有 xmlns 特性,这些特性将适用于定义元素的任何子代元素。但是,频繁定义或重新定义 XAML 命名空间可能会导致 XAML 标记样式难以阅读。
其 XAML 处理器的 WPF 实现包括可识别 WPF 核心程序集的基础结构。已知 WPF 核心程序集包含支持 WPF 到默认 XAML 命名空间的映射的类型。这是通过属于项目生成文件以及 WPF 生成和项目系统一部分的配置来实现的。因此,为了引用来自 WPF 程序集的 XAML 元素,只需将默认 XAML 命名空间声明为默认 xmlns。
<b>x: </b><b>前</b><b>缀</b>
在上面的根元素示例中,前缀 x: 用于映射 XAML 命名空间 http://schemas.microsoft.com/winfx/2006/xaml,该命名空间是支持 XAML 语言构造的专用 XAML 命名空间。在这整个 SDK 的项目模板、示例以及文档中,此 x: 前缀用于映射该 XAML 命名空间。XAML 语言的 XAML 命名空间包含多个将在 XAML 中频繁用到的编程构造。下面列出了将用到的最常见的 x: 前缀编程构造:
<b>XAML </b><b>中的自定</b><b>义</b><b>前</b><b>缀</b><b>和自定</b><b>义类</b><b>型</b>
对于您自己的自定义程序集或 PresentationCore、PresentationFramework 和 WindowsBase 的 WPF 核心以外的程序集,可以将该程序集指定为自定义 xmlns 映射的一部分。只要该类型能够正确地实现以支持您所尝试的 XAML 用法,就可以在 XAML 中引用该程序集中的类型。
下面是一个说明自定义前缀如何在 XAML 标记中工作的基本示例。前缀 custom 在根元素标记中定义,并映射为随应用程序一同打包并可用于该应用程序的一个特定程序集。此程序集包含 NumericUpDown 类型,实现该类型的目的是在支持常规 XAML 用法之外,还可以使用允许在 WPF XAML 内容模型的此特定点执行插入的类继承。通过使用该前缀,此 NumericUpDown 控件的一个实例声明为对象元素,以便 XAML 分析器可找到包含该类型的 XAML 命名空间,从而找到包含该类型定义的后备程序集的位置。
xmlns:custom="clr-namespace:NumericUpDownCustomControl;assembly=CustomLibrary"
>
<StackPanel Name="LayoutRoot">
<custom:NumericUpDown Name="numericCtrl1" Width="100" Height="60"/>
...</StackPanel>
<b>事件和</b><b> XAML </b><b>代</b><b>码隐</b><b>藏</b>
大多数 WPF 应用程序既包括 XAML 标记,也包括代码隐藏。在一个项目中,XAML 编写为 .xaml 文件,而 CLR 语言(如 Microsoft Visual Basic .NET 或 C#)用于编写代码隐藏文件。在 WPF 编程和应用程序模型中对 XAML 文件进行标记编译时,XAML 文件的 XAML 代码隐藏文件的位置是通过如下方式来标识的:以 XAML 的根元素的 x:Class 特性形式指定一个命名空间和类。
在目前已介绍的示例中,您已看到几个按钮,但还没有一个按钮具有任何关联的逻辑行为。为对象元素添加行为的主要应用程序级机制是使用元素类的现有事件,并为在运行时引发该事件时调用的该事件编写特定的处理程序。事件名称以及要使用的处理程序的名称在标记中指定,而实现处理程序的代码在代码隐藏中定义。
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim b As Button = e.Source
b.Foreground = Brushes.Red
End Sub
请注意,代码隐藏文件使用 CLR 命名空间 ExampleNamespace 并将 ExamplePage 声明为该命名空间内的一个分部类。这相当于在标记根中提供的 ExampleNamespace.ExamplePage 的 x:Class 特性值。WPF 标记编译器将通过从根元素类型派生一个类,为编译的任何 XAML 文件创建一个分部类。当您提供也会定义同一分部类的代码隐藏时,将在与编译的应用程序相同的命名空间和类中组合生成的代码。
<b>路由事件</b>
<b>XAML </b><b>命名元素</b>
<StackPanel Name="buttonContainer">
<Button Click="RemoveThis">Click to remove this button</Button>
Private Sub RemoveThis(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim fe As FrameworkElement = e.Source
If (buttonContainer.Children.Contains(fe)) Then
buttonContainer.Children.Remove(fe)
End If
<b>附加属性和附加事件</b>
XAML 指定了一个语言功能,该功能允许对任何元素指定某些属性或事件,而不管要设置属性或事件的元素的类型定义中是否存在该属性或事件。该功能的属性版本称为附加属性,事件版本称为附加事件。从概念上讲,可以将附加属性和附加事件视为可以在任何 XAML 元素/对象实例上设置的全局成员。但是,元素/类或更大的基础结构必须支持附加值的后备属性存储。
通常通过特性语法来使用 XAML 中的附加属性。在特性语法中,您可以采用“所有者类型.属性名”的形式指定附加属性。
表面上,这与属性元素用法类似,但在这种情况下,您指定的“所有者类型”始终是一种与从中要设置附加属性的对象元素不同的类型。“所有者类型”这种类型提供 XAML 处理器为获取或设置附加属性值所需要的访问器方法。
使用附加属性的最常见方案是使子元素能够向其父元素报告属性值。
<DockPanel>
<Button DockPanel.Dock="Left" Width="100" Height="20">I am on the left</Button>
<Button DockPanel.Dock="Right" Width="100" Height="20">I am on the right</Button>
</DockPanel>
本文转自linzheng 51CTO博客,原文链接:http://blog.51cto.com/linzheng/1079236