65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 导览 - 第一部分 (XAML)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (194投票s)

2007 年 4 月 1 日

CPOL

7分钟阅读

viewsIcon

889292

downloadIcon

36957

Windows Presentation Foundation 的导览,一次介绍一个功能。

The WPF Horse Race application in action.

目录

  • 第一部分 (XAML):了解 XAML 及其在 WPF 应用程序中的使用。
  • 第 2 部分 (布局):了解布局面板及其如何用于构建用户界面。
  • 第 3 部分 (数据绑定):了解 WPF 数据绑定如何工作以及如何使用。
  • 第四部分 (数据模板和触发器):了解数据模板和触发器是如何工作的以及如何使用它们。
  • 第 5 部分 (样式):了解 WPF 中如何设置 UI 样式。

引言

本文是介绍 Microsoft Windows Presentation Foundation (WPF) 一些重要特性的系列文章中的第一篇。整个系列的文章只是触及了 WPF 庞大平台的皮毛,并且不会深入探讨任何特定主题。本系列的目的是让读者熟悉 WPF 的基本编程模型,以便他们能够充分理解(相当不怎么样的)WPF 赛马应用程序(可在页面顶部的链接处下载)。

主题内容以一个完全不切实际的赛马应用程序为背景,如上面的截图所示。该应用程序的设计初衷是作为本系列文章的重点。我试图在使演示应用程序足够简单以便 WPF 新手能够理解,同时又足够复杂以便能够实际做一些有趣(或者至少是有点好笑)的事情之间找到平衡。

必备组件

为了运行 WPF 应用程序,您需要 .NET Framework 3.0 或更高版本。Windows Vista 默认安装了 .NET Framework v3.0,所以只有在您使用 Windows XP SP2 时才需要安装它。

要开发 WPF 应用程序,您应该拥有 Visual Studio 2005 和“Orcas”扩展,或者更高版本的 Visual Studio,以及 Windows SDK。有关相关资源的链接,请参阅本文末尾的外部链接部分。

什么是 XAML?

XAML 是 eXtensible Application Markup Language(可扩展应用程序标记语言)的缩写。它是一种通用的基于 XML 的语言,用于声明在运行时实例化的对象图。WPF 开发人员使用 XAML 来声明用户界面 (UI) 的布局以及该 UI 中使用的资源。

在使用 WPF 进行编程时,使用 XAML 并非绝对必要。XAML 中能完成的任何事情都可以通过代码完成。使用 XAML 可以使许多 UI 开发场景更加简单快捷,例如创建 UI 布局以及配置样式、模板和其他 WPF 特定的实体(这些将在本系列的后面章节中讨论)。

性能影响

当您在 Visual Studio 中编译 WPF 应用程序时,它会将您的 XAML 文件编译成一种称为二进制应用程序标记语言 (BAML) 的压缩表示形式。然后,BAML 将作为资源保存在生成的程序集中。当加载该程序集并请求该资源时,BAML 会被流式输出并非常快速地转换为由原始 XAML 所描述的对象图。

这个两步过程允许在编译时进行 XAML 解析,从而减轻了使用基于文本的对象实例化技术的性能开销。也就是说,可以通过 XamlReader.Load 方法以编程方式加载 XAML。动态加载 XAML 在多种情况下可能很有用,例如当 UI 中易变的部分会通过 XML Web 服务定期从服务器下载时。

基本语法

由于 XAML 是一种基于 XML 的语言,因此对于任何有 XML 经验的人来说,它应该相当简单明了。XML 元素在 XAML 中有两种不同的用途:代表对象的元素和代表对象属性的元素。XML 属性始终代表对象的一个属性或事件。就是这样;就这么简单。在这些基本概念之上还构建了一些其他概念,但 XAML 从来不会变得复杂。

例如

<Button Content="Click Me" Click="OnButtonClick">
  <Button.Background>
    <LinearGradientBrush>
      <GradientStop Color="Yellow" Offset="0" />
      <GradientStop Color="Green" Offset="1" />
    </LinearGradientBrush>
  </Button.Background>
</Button>

XAML 会生成一个别致的小按钮,它渲染效果如下:

A Button, as configured by the preceding XAML

让我们来解析一下这段 XAML,看看它是如何工作的。<Button> 元素声明将创建一个 Button 类的实例。该 Button 对象将其 Content 属性设置为字符串 "Click Me"ButtonClick 事件将由代码隐藏文件中的一个名为 OnButtonClick 的方法处理(我们很快会介绍代码隐藏文件)。

下一个元素是 <Button.Background>,它被称为使用“属性元素语法”。该 XML 元素代表正在配置的 ButtonBackground 属性。属性元素的子元素是属性被设置的值。在这种情况下,Background 属性被设置为一个 LinearGradientBrush 对象。

该画笔有两个 <GradientStop> 子元素,这乍一看可能令人困惑。这些 GradientStop 对象在做什么?它们被分配或添加到哪里?答案在于 XAML 内置了一些“快捷方式”,允许您为一个类指定一个被认为是“内容属性”的属性。您不需要使用属性元素语法为类的“内容属性”分配值。由于 LinearGradientBrush 的内容属性是 GradientStops 属性,因此以下 XAML 与上面所示的等价:

<Button Content="Click Me" Click="OnButtonClick">
  <Button.Background>
    <LinearGradientBrush>
      <LinearGradientBrush.GradientStops>
        <GradientStop Color="Yellow" Offset="0" />
        <GradientStop Color="Green" Offset="1" />
      <LinearGradientBrush.GradientStops>
    </LinearGradientBrush>
  </Button.Background>
</Button>

C# 版本

如果您想知道用 C# 编写这段 XAML 会是什么样子,下面是转换后的代码:

Button b = new Button();
b.Content = "Click Me";
b.Click += this.OnButtonClick;
LinearGradientBrush lgb = new LinearGradientBrush();
lgb.GradientStops.Add( new GradientStop( Colors.Yellow, 0 ) );
lgb.GradientStops.Add( new GradientStop( Colors.Green, 1 ) );
b.Background = lgb;

标记扩展

XAML 解析器还知道如何处理一种称为“标记扩展”的特殊构造。标记扩展允许您紧凑地配置对象并引用应用程序中其他位置定义的 other objects。它们用于在设置对象属性时,通过 XML 属性或属性元素语法。标记扩展用于诸如指定 null 值、声明数组、引用资源字典中保存的对象、将一个属性绑定到另一个属性等等。

以下 XAML 大致等价于前面示例(有一些小的改动)

<Grid>
  <Grid.Resources>
    <LinearGradientBrush x:Key="FunkyBrush">
      <GradientStop Color="Yellow" Offset="0" />
      <GradientStop Color="Green" Offset="1" />
    </LinearGradientBrush>
  </Grid.Resources>
  <Button Background="{StaticResource FunkyBrush}">Click Me</Button>
</Grid>

请注意,ButtonBackground 属性通过 XML 属性设置为 {StaticResource FunkyBrush}。当属性设置为以 { 开头并以 } 结尾的值时,则正在使用标记扩展。

在这种情况下,StaticResourceExtension 类被用于引用存储在 Grid 的资源字典中的 LinearGradientBrush。(注意:Grid 是 WPF 中的一个布局面板,而不是像您可能预期的那样用于呈现表格数据的控件。)

代码隐藏文件

XAML 会被编译成一个类。除非您指定了它应该使用的类名,否则编译器会为您生成一个类名。然而,当您在 XAML 文件中的根 XML 元素上应用 x:Class 属性时,您可以在 C# 或 VB.NET 中创建一个部分类,该类将与 XAML 部分类合并。这就是您可以将行为与 XAML 中声明的布局和视觉效果关联起来的方式。

例如,在上面的演示中,我们在 XAML 中创建了一个 Button,并为其 Click 事件分配了一个事件处理方法。OnButtonClick 方法将在代码隐藏文件中定义,该文件包含与 XAML 生成的部分类相关联的类的另一个部分。

假设我们讨论的 Button 位于一个名为 MyWindowWindow 子类中。代码隐藏文件(*MyWindow.xaml.cs*)如下所示:

public partial class MyWindow : Window
{
 public MyWindow()
 {
  InitializeComponent();
 }
 void OnButtonClick( object sender, RoutedEventArgs e )
 {
  MessageBox.Show( "Click me again.  That felt good." );
 }
}

WPF 赛马应用程序如何使用 XAML

WPF 赛马应用程序几乎完全是用 XAML 编写的。该应用程序使用三个 C# 文件:主 Window 的代码隐藏文件、一个 RaceHorse 类的文件,以及另一个包含一些值转换器(关于这些内容将在关于数据绑定的文章中进一步介绍)。应用程序的其余部分全部在 XAML 中。

我鼓励您探索 WPF 赛马应用程序的源代码文件,并查看 XAML 在创建实际程序(而不是仅仅作为简单演示)时是什么样子的。本系列文章的其余部分将探讨整个应用程序的工作原理,但没有什么比现在就深入源代码文件并自己探索它是如何工作的更好的了。

外部链接

必备组件

XAML

WPF 常规提示

历史

  • 2007 年 4 月 1 日 - 创建了文章。
  • 2007 年 4 月 3 日 - 从 RaceHorseDataTemplate.xaml 中的 Grid 中删除了多余的 ColumnDefinitions,并更新了演示项目下载文件。
  • 2007 年 4 月 18 日 - 修正了关于标记扩展的一个不准确的说法。我最初声称它们仅与 XML 属性一起使用,但它们也可以与属性元素语法一起使用。
© . All rights reserved.