WPF学习之路初识
WPF学习之路初识
WPF 介绍
Windows Presentation Foundation (WPF) 是下一代显示系统,用于生成能带给用户震撼视觉体验的 Windows 客户端应用程序。 使用 WPF,您可以创建广泛的独立应用程序以及浏览器承载的应用程序。示例包括下图中显示的 Contoso Healthcare Sample Application(Contoso Healthcare 示例应用程序)。
WPF 的核心是一个与分辨率无关并且基于向量的呈现引擎,旨在利用现代图形硬件的优势。WPF 通过一整套应用程序开发功能扩展了这个核心,这些功能包括可扩展应用程序标记语言 (XAML)、控件、数据绑定、布局、二维和三维图形、动画、样式、模板、文档、媒体、文本和版式。WPF 包含在 Microsoft .NET Framework 中,使您能够生成融入了 .NET Framework 类库的其他元素的应用程序。
WPF 作为 .NET Framework 类型的一个子集存在,这些类型大多位于 System.Windows 命名空间。如果您以前已使用 .NET Framework 通过诸如 ASP.NET 和 Windows 窗体之类的托管技术生成应用程序,那么您应该熟悉 WPF 的基本编程体验;您可以使用您最喜爱的 .NET Framework 编程语言(如 C# 或 Visual Basic)实例化类、设置属性、调用方法以及处理事件。
WPF 为 Windows 客户端应用程序开发提供了更多编程增强功能。 一个明显的增强功能就是使用标记和代码隐藏开发应用程序的功能,ASP.NET 开发人员应该熟悉此体验。 您通常使用可扩展应用程序标记语言 (XAML) 标记实现应用程序的外观,而使用托管编程语言(代码隐藏)实现其行为。 这种外观和行为的分离具有以下优点:
-
降低了开发和维护成本,因为外观特定的标记并没有与行为特定的代码紧密耦合。
-
开发效率更高,因为设计人员可以在开发人员实现应用程序行为的同时实现应用程序的外观。
-
可以使用多种设计工具实现和共享 XAML 标记,以满足应用程序开发参与者的要求;Microsoft Expression Blend 提供了适合设计人员的体验,而 Visual Studio 2005 针对开发人员。
-
WPF 应用程序的全球化和本地化得以大大简化(请参见 WPF 全球化和本地化概述)。
标记
XAML 是一种基于 XML 的标记语言,用于以声明的方式实现应用程序的外观。它通常用于创建窗口、对话框、页面和用户控件,并用控件、形状和图形填充它们。
下面的示例使用 XAML 实现一个窗口的外观,该窗口中只包含一个按钮。
具体而言,此 XAML 分别使用 Window 和 Button 元素定义一个窗口和一个按钮。 每个元素均配置了特性,如 Window 元素的 Title 特性,用于指定窗口的标题栏文本。在运行时,WPF 将标记中定义的元素和特性转换为 WPF 类的实例。 例如,Window 元素被转换为 Window 类的实例,该类的 Title 属性是 Title 特性的值。
下图演示了 XAML 在上一示例中定义的用户界面 (UI)。
参见 XAML 概述 (WPF)。
由于 XAML 基于 XML,因此使用它来编写的 UI 被组合到称为“元素树”的嵌套元素层次结构中。 元素树为创建和管理 UI 提供了一种逻辑且直观的方式。 有关更多信息,请参见 WPF 中的树。
代码隐藏
应用程序的主要行为是实现响应用户交互的功能,包括处理事件(如,单击菜单、工具栏或按钮),并调用业务逻辑和数据访问逻辑作为响应。 在 WPF 中,此行为通常在与标记关联的代码中实现。 此类代码称为“代码隐藏”。 下面的示例演示上一示例中的代码隐藏和更新的标记。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.AWindow" Title="Window with Button" Width="250" Height="100"> <!-- Add button to window --> <Button Name="button" Click="button_Click">Click Me!</Button> </Window>
Namespace SDKSample Partial Public Class AWindow Inherits System.Windows.Window Public Sub New() ' InitializeComponent call is required to merge the UI ' that is defined in markup with this class, including ' setting properties and registering event handlers InitializeComponent() End Sub Private Sub button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) ' Show message box when button is clicked MessageBox.Show("Hello, Windows Presentation Foundation!") End Sub End Class End Namespace
using System.Windows; // Window, RoutedEventArgs, MessageBox namespace SDKSample { public partial class AWindow : Window { public AWindow() { // InitializeComponent call is required to merge the UI // that is defined in markup with this class, including // setting properties and registering event handlers InitializeComponent(); } void button_Click(object sender, RoutedEventArgs e) { // Show message box when button is clicked MessageBox.Show("Hello, Windows Presentation Foundation!"); } } }
在此示例中,代码隐藏实现一个从 Window 类派生的类。 x:Class 特性用于将标记与代码隐藏类相关联。 InitializeComponent 是从代码隐藏类的构造函数中调用的,用于将标记中定义的 UI 与代码隐藏类相合并。 (生成应用程序时将为您生成 InitializeComponent,因此您不需要手动实现它。)x:Class 和 InitializeComponent 的组合确保您的实现无论何时创建都能得到正确的初始化。 代码隐藏类还为按钮的 Click 事件实现了一个事件处理程序。 当单击该按钮时,事件处理程序将通过调用 MessageBox.Show 方法显示一个消息框。
下图演示了单击按钮后的结果。
.NET Framework、System.Windows、标记和代码隐藏构成了 WPF 应用程序开发体验的基础。 此外,WPF 还为创造具有丰富内容的用户体验提供了全面的功能。 为了打包此内容并将其作为“应用程序”发送给用户,WPF 提供了一些类型和服务,它们统称为“应用程序模型”。 该应用程序模型既支持开发独立应用程序,也支持开发浏览器承载的应用程序。
独立应用程序
对于独立应用程序,您可以使用 Window 类创建可从菜单栏和工具栏上访问的窗口和对话框。 下图演示了带有一个主窗口和一个对话框的独立应用程序。
此外,您还可以使用以下 WPF 对话框:MessageBox、OpenFileDialog、SaveFileDialog 和 PrintDialog。
浏览器承载的应用程序
对于浏览器承载的应用程序(称为 XAML 浏览器应用程序 (XBAP)),您可以创建能够使用超链接(Hyperlink 类)导航的页面 (Page) 和页函数 (PageFunction<T>)。 下图演示了 Internet Explorer 7 承载的 XBAP 中的页面。
WPF 应用程序既可以承载于 Microsoft Internet Explorer 6 中,也可以承载于 Internet Explorer 7 中。 WPF 提供了以下两个选项作为替代导航宿主:
-
Frame ,用于承载页面或窗口中可导航内容的孤岛。
-
NavigationWindow ,用于承载整个窗口中的可导航内容。
参见导航概述。
应用程序类
XBAP 和独立应用程序通常非常复杂,需要额外的应用程序范围的服务,包括启动和生存期管理、共享属性以及共享资源。Application 类封装了这些服务以及更多内容,并且只需使用 XAML 即可实现,如下面的示例所示。
此标记是独立应用程序的应用程序定义,并指示 WPF 创建一个在应用程序启动时自动打开 MainWindow 的 Application 对象。
理解 Application 的一个关键概念在于,它为独立应用程序和浏览器承载的应用程序提供了一个通用的支持平台。 例如,浏览器承载的应用程序可以使用前面的 XAML,以便在 XBAP 启动时自动导航到某个页面,如下面的示例所示。
有关更多信息,请参见应用程序管理概述。
安全性
由于 XBAP 承载于浏览器中,因此安全性至关重要。 特别是,XBAP 使用部分信任的安全性沙盒强制施加限制,这些限制少于或等于对基于 HTML 的应用程序所施加的限制。 此外,可以从部分信任的 XBAP 中安全运行的每个 HTML 功能都使用全面的安全进程进行了测试,WPF 安全策略 — 安全工程中对此进行了详细介绍。
尽管如此,大部分 WPF 功能仍能够从 XBAP 中安全执行,如 WPF 部分信任安全中所述。
应用程序模型提供的用户体验是构造控件。 在 WPF 中,“控件”是一个总括性术语,适用于窗口或页面中承载的、具有用户界面 (UI) 并且实现某些行为的一种 WPF 类。
参见控件。
按功能分类的 WPF 控件
此处列出了内置的 WPF 控件。
-
按钮:Button 和 RepeatButton。
-
日期显示和选择:Calendar 和 DatePicker。
-
数字墨迹:InkCanvas 和 InkPresenter。
-
文档:DocumentViewer、FlowDocumentPageViewer、FlowDocumentReader、FlowDocumentScrollViewer 和 StickyNoteControl。
-
输入:TextBox、RichTextBox 和 PasswordBox。
-
布局:Border、BulletDecorator、Canvas、DockPanel、Expander、Grid、GridView、GridSplitter、GroupBox、Panel、ResizeGrip、Separator、ScrollBar、ScrollViewer、StackPanel、Thumb、Viewbox、VirtualizingStackPanel、Window 和 WrapPanel。
-
菜单:ContextMenu、Menu 和 ToolBar。
-
选择:CheckBox、ComboBox、ListBox、RadioButton 和 Slider。
-
用户信息:AccessText、Label、Popup、ProgressBar、StatusBar、TextBlock 和 ToolTip。
创建 UI 时,您通过按位置和大小排列控件来形成一种布局。 任何布局的主要要求都是适应窗口大小和显示设置的变化。 WPF 为您提供了一个一流的可扩展布局系统,而不是强制您编写代码以使布局适应这些情况。
布局系统的基础是相对定位,它提高了适应窗口和显示条件变化的能力。 此外,布局系统还管理控件之间的协商以确定布局。 协商过程分为两步:第一步,控件向父控件通知它所需的位置和大小;第二步,父控件通知该控件它可以具有多大空间。
布局系统通过基本 WPF 类公开给子控件。对于通用的布局,如网格、堆叠和停靠,WPF 包括了几个布局控件:
-
Canvas :子控件提供其自己的布局。
-
DockPanel :子控件与面板的边缘对齐。
-
Grid :子控件按行和列放置。
-
StackPanel :子控件垂直或水平堆叠。
-
VirtualizingStackPanel :子控件被虚拟化,并沿水平或垂直方向排成一行。
-
WrapPanel :子控件按从左到右的顺序放置,如果当前行中的控件数多于该空间所允许的控件数,则换至下一行。
下面的示例使用 DockPanel 排列几个 TextBox 控件。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.LayoutWindow" Title="Layout with the DockPanel" Height="143" Width="319"> <!--DockPanel to layout four text boxes--> <DockPanel> <TextBox DockPanel.Dock="Top">Dock = "Top"</TextBox> <TextBox DockPanel.Dock="Bottom">Dock = "Bottom"</TextBox> <TextBox DockPanel.Dock="Left">Dock = "Left"</TextBox> <TextBox Background="White">This TextBox "fills" the remaining space.</TextBox> </DockPanel> </Window>
DockPanel 允许子 TextBox 控件通知它如何排列这些子控件。 为此,DockPanel 实现一个 Dock 属性,该属性公开给子控件,以便每个子控件指定一个停靠样式。
下图演示了上一示例中 XAML 标记的结果。
有关更多信息,请参见布局。 有关介绍性示例,请参见 WPF Layout Gallery Sample(WPF 布局库示例)。
创建大多数应用程序的目的是为用户提供查看和编辑数据的方式。 对于 WPF 应用程序,存储和访问数据的工作已经由 Microsoft SQL Server 和 ADO.NET 之类的技术提供。 访问数据并将数据加载到应用程序的托管对象中后,WPF 应用程序的复杂工作才开始。 实质上它涉及到两个步骤:
-
将数据从托管对象复制到控件中,在控件上可以显示和编辑数据。
-
确保将使用控件对数据进行的更改复制回托管对象。
为了简化应用程序开发,WPF 提供了一个数据绑定引擎以自动执行这些步骤。数据绑定引擎的核心单元是 Binding 类,它的任务是将控件(绑定目标)绑定到数据对象(绑定源)。 下图说明了这种关系。
下面的示例演示如何将 TextBox 绑定到自定义 Person 对象的实例。 下面的代码演示了 Person 的实现。
下面的标记将 TextBox 绑定到自定义 Person 对象的实例。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.DataBindingWindow"> ... <!-- Bind the TextBox to the data source (TextBox.Text to Person.Name) --> <TextBox Name="personNameTextBox" Text="{Binding Path=Name}" /> ... </Window>
Imports System.Windows ' Window Namespace SDKSample Partial Public Class DataBindingWindow Inherits Window Public Sub New() InitializeComponent() ' Create Person data source Dim person As Person = New Person() ' Make data source available for binding Me.DataContext = person End Sub End Class End Namespace
在此示例中,Person 类在代码隐藏中实例化,并被设置为 DataBindingWindow 的数据上下文。 在标记中,将 TextBox 的 Text 属性绑定到 Person.Name 属性(使用“{Binding ... }”XAML 语法)。 此 XAML 通知 WPF 将 TextBox 控件绑定到存储在窗口的 DataContext 属性中的 Person 对象。
WPF 数据绑定引擎还提供了其他支持,包括验证、排序、筛选和分组。 此外,当标准 WPF 控件显示的 UI 不合适时,数据绑定还支持使用数据模板为绑定的数据创建自定义 UI。
有关更多信息,请参见数据绑定概述。 有关介绍性示例,请参见 Data Binding Demo(数据绑定演示)。
WPF 引进了一组广泛的、可伸缩且灵活的图形功能,它们具有以下优点:
-
与分辨率和设备无关的图形。 WPF 图形系统的基本度量单位是与设备无关的像素,它等于一英寸的 1/96,而不管实际的屏幕分辨率是多少,为与分辨率和设备无关的呈现提供了基础。 每个与设备无关的像素都会自动缩放,以符合呈现该像素的系统上的每英寸点数 (dpi) 设置。
-
更高的精度。 WPF 坐标系是使用双精度浮点数字测量的,而不是使用单精度浮点数字。 转换值和不透明度值也以双精度表示。 WPF 还支持广泛的颜色域 (scRGB),并为管理来自不同颜色空间的输入提供了完整的支持。
-
高级图形和动画支持。 WPF 通过为您管理动画场景简化了图形编程;您不需要担心场景处理、呈现循环和双线性内插算法。 此外,WPF 还提供了命中测试支持和全面的 alpha 合成支持。
-
硬件加速。 WPF 图形系统利用了图形硬件的优势来最小化 CPU 使用率。
二维形状
WPF 提供了一个库,包含用矢量绘制的通用二维形状,如下图中演示的矩形和椭圆。
形状具有一个有趣的功能:它们不仅仅用于显示,还实现了您可以从控件中获得的许多功能,包括键盘和鼠标输入。 下面的示例演示正在处理的 Ellipse 的 MouseUp 事件。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.EllipseEventHandlingWindow" Title="Click the Ellipse"> <Ellipse Name="clickableEllipse" Fill="Blue" MouseUp="clickableEllipse_MouseUp" /> </Window>
Imports System.Windows ' Window, MessageBox Imports System.Windows.Input ' MouseButtonEventArgs Namespace SDKSample Public Class EllipseEventHandlingWindow Inherits Window Public Sub New() InitializeComponent() End Sub Private Sub clickableEllipse_MouseUp(ByVal sender As Object, ByVal e As MouseButtonEventArgs) MessageBox.Show("You clicked the ellipse!") End Sub End Class End Namespace
using System.Windows; // Window, MessageBox using System.Windows.Input; // MouseButtonEventHandler namespace SDKSample { public partial class EllipseEventHandlingWindow : Window { public EllipseEventHandlingWindow() { InitializeComponent(); } void clickableEllipse_MouseUp(object sender, MouseButtonEventArgs e) { // Display a message MessageBox.Show("You clicked the ellipse!"); } } }
下图演示了以上代码生成的结果。
有关更多信息,请参见 WPF 中的形状和基本绘图概述。 有关介绍性示例,请参见 Shape Elements Sample(形状元素示例)。
二维几何图形
WPF 提供的二维形状涵盖了基本形状的标准集合。 但是,您可能需要创建自定义形状以帮助设计自定义的 UI。 出于此目的,WPF 提供了几何图形。 下图演示了使用几何图形创建一个可以直接绘制、用作画笔或用于剪裁其他形状和控件的自定义形状。
Path 对象可用于绘制闭合或开放形状、多线形状,甚至曲线形状。
Geometry 对象可用于对二维图形数据进行剪裁、命中测试和呈现。
有关更多信息,请参见Geometry 概述。 有关介绍性示例,请参见 Geometries Sample(几何图形示例)。
二维效果
WPF 二维功能的子集包括渐变、位图、绘图、视频绘制、旋转、缩放和扭曲等视觉效果。 这些都可以使用画笔完成;下图演示了某些示例。
有关更多信息,请参见 WPF 画笔概述。 有关介绍性示例,请参见 Brushes Sample(画笔示例)。
三维呈现
WPF 还包括三维呈现功能,这些功能可以与二维图形进行集成,以便于创建更激动人心、更有趣的 UI。 例如,下图演示了呈现在三维形状上的二维图像。
有关更多信息,请参见三维图形概述。 有关介绍性示例,请参见 3-D Solids Sample(三维实体示例)。
WPF 动画支持可以使控件变大、旋转、调节和淡化,以产生有趣的页面过渡和更多效果。 您可以对大多数 WPF 类(甚至自定义类)进行动画处理。 下图演示了一个简单的活动动画。
请参见动画概述。 Animation Example Gallery(动画示例库)。
传达丰富内容的一个方法是使用视听媒体。 WPF 为图像、视频和音频提供了特殊的支持。
图像
图像对大多数应用程序来说都很常见,WPF 提供了几种方式来使用图像。 下图演示了具有一个列表框的 UI,该列表框中包含缩略图图像。 当选中一个缩略图时,该图像将以完整大小显示。
参见图像处理概述。
视频和音频
MediaElement 控件既可以播放视频,也可以播放音频,它的灵活程度使其足以用作自定义媒体播放器的基础。 下面的 XAML 标记实现一个媒体播放器。
下图中的窗口演示 MediaElement 活动控件。
有关更多信息,请参见 图形和多媒体。
为了加快高质量的文本呈现,WPF 提供了以下功能:
-
OpenType 字体支持。
-
ClearType 增强。
-
利用硬件加速优势的高性能。
-
文本与媒体、图形和动画的集成。
-
国际字体支持和回退机制。
为了说明文本与图形的集成,下图演示了文本效果的应用。
有关更多信息,请参见 WPF 中的版式。
WPF 本身支持使用三种类型的文档:流文档、固定文档和 XML 纸张规范 (XPS) 文档。 WPF 还提供了用于创建、查看、管理、批注、打包和打印文档的服务。
流文档
流文档的设计用途是,当窗口大小和显示设置发生变化时,通过动态调整和回流内容来优化查看和可读性。 下面的 XAML 标记演示了FlowDocument的定义。
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <Paragraph FontSize="18" FontWeight="Bold">Flow Document</Paragraph> <Paragraph> Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure. </Paragraph> ... </FlowDocument>
下面的示例演示如何将流文档加载到 FlowDocumentReader 中以进行查看、搜索和打印。
Imports System.Windows 'Window Imports System.Windows.Documents 'FlowDocument Imports System.IO 'FileStream, FileMode Imports System.Windows.Markup 'XamlReader Namespace SDKSample Public Class FlowDocumentReaderWindow Inherits Window Public Sub New() Me.InitializeComponent() Using stream1 As FileStream = New FileStream("AFlowDocument.xaml", _ FileMode.Open, FileAccess.Read) Dim document1 As FlowDocument = _ TryCast(XamlReader.Load(stream1), FlowDocument) Me.flowDocumentReader.Document = document1 End Using End Sub End Class End Namespace
using System.Windows; // Window using System.Windows.Documents; // FlowDocument using System.IO; // FileStream, FileMode using System.Windows.Markup; // XamlReader namespace SDKSample { public partial class FlowDocumentReaderWindow : System.Windows.Window { public FlowDocumentReaderWindow() { InitializeComponent(); // Open the file that contains the FlowDocument using (FileStream xamlFile = new FileStream("AFlowDocument.xaml", FileMode.Open, FileAccess.Read)) { // Parse the file with the XamlReader.Load method FlowDocument content = XamlReader.Load(xamlFile) as FlowDocument; // Set the Document property to the parsed FlowDocument object this.flowDocumentReader.Document = content; } } } }
下面的示例演示了结果。
有关更多信息,请参见流文档概述。
固定文档
固定文档适用于需要精确的“所见即所得”(WYSIWYG) 演示的应用程序,尤其是对于打印。 固定文档的典型用途包括桌面发布、字处理和窗体布局,在这些情况下,遵循原始页面设计非常关键。
固定文档通过与设备无关的方式维护了文档内容的精确排列。 例如,一个固定文档在 96 dpi 显示器上显示的效果与在 600 dpi 激光打印机或 4800 dpi 照相排字机上打印的效果是一样的。 虽然文档的质量会因每台设备的功能不同而有所不同,但是布局在所有情况下都保持不变。
有关更多信息,请参见 WPF 中的文档。
XPS 文档
XML 纸张规范 (XPS) 文档建立在 WPF 的固定文档基础上。 XPS 文档使用基于 XML 的架构进行描述,该架构本质上就是电子文件的分页表示。 XPS 是一个开放的、跨平台的文档格式,旨在简化分页文档的创建、共享、打印和存档。 XPS 技术的重要功能包括:
-
将 XPS 文档打包为符合 Open Packaging Conventions(开放打包约定,OPC)的 ZipPackage 文件。
-
由独立应用程序和基于浏览器的应用程序承载。
-
从 WPF 应用程序中手动生成和操作 XPS 文档。
-
通过追求最大化输出设备质量进行高保真呈现。
-
Windows Vista 后台打印。
-
将文档直接传送到与 XPS 兼容的打印机。
-
UI 与 DocumentViewer 集成。
下图演示由 DocumentViewer 显示的 XPS 文档。
DocumentViewer 还允许用户更改视图、搜索和打印 XPS 文档。
有关更多信息,请参见 WPF 中的文档。
批注
批注是在文档中添加的说明或注释,用于标记信息或突出显示相关项目,以便于以后参考。 尽管在打印文档上编写说明很容易,但在电子文档上“编写”说明的功能常常受到限制或者不可用。 但是,WPF 中提供了一个批注系统,以支持粘滞便筏和突出显示。 此外,这些批注还可应用于 DocumentViewer 控件中承载的文档,如下图所示。
有关更多信息,请参见批注概述。
打包
WPF System.IO.Packaging API 允许您的应用程序将数据、内容和资源组织成一个可移植、易于分发和访问的 ZIP 文档。 可以包括数字签名以对程序包中包含的项目进行身份验证,并确定签名的项目未被篡改或修改。 您还可以使用权限管理对软件包进行加密,以限制对受保护信息的访问。
有关更多信息,请参见 WPF 中的文档。
打印
.NET Framework 包括一个打印子系统,WPF 通过支持更好的打印系统控制对其进行了增强。 打印增强功能包括:
-
实时安装远程打印服务器和队列。
-
动态发现打印机功能。
-
动态设置打印机选项。
-
打印作业重新路由和重新排列优先级别次序。
XPS 文档还包含一个关键的性能改进功能。 现有的 Microsoft Windows 图形设备接口 (GDI) 打印路径通常需要两次转换:
-
第一次是将文档转换成打印处理器格式,如增强型图元文件 (EMF)。
-
第二次是转换成打印机的页面描述语言,如打印机控制语言 (PCL) 或 PostScript。
但是,XPS 文档避免了这些转换,因为 XPS 文件格式的一个组件是打印处理器语言和页面描述语言。 这项支持有助于减少打印后台文件的大小和网络打印机的负载。
有关更多信息,请参见打印概述。
到目前为止,您已经看到了开发应用程序的核心 WPF 生成块。 您可以使用应用程序模型承载和提供主要由控件构成的应用程序内容。 若要简化 UI 中的控件排列,并确保在窗口大小和显示设置更改时维护这种排列,请使用 WPF 布局系统。 由于大多数应用程序都允许用户与数据交互,因此您可以使用数据绑定减少将 UI 与数据相集成的工作量。若要改进应用程序的视觉外观,请使用 WPF 提供的各种图形、动画和媒体支持。 最后,如果您的应用程序通过文本和文档进行操作,您可以使用 WPF 文本、版式、文档、批注、打包和打印功能。
尽管如此,基本功能通常不足以创建和管理真正与众不同、具有视觉震撼力的用户体验。 标准 WPF 控件可能不能与所需的应用程序外观集成。 数据可能不能以最有效的方式显示。 应用程序的整体用户体验可能不适合 Windows 主题的默认外观。 在很多方面,演示技术需要具有像其他任何扩展性那样多的视觉扩展性。
出于这个原因,WPF 为创建独特的用户体验提供了各种机制,包括一个内容丰富的模型,用于控件、触发器、控件和数据模板、样式、UI 资源以及主题和外观。
内容模型
大多数 WPF 控件的主要目的都是为了显示内容。 在 WPF 中,构成控件内容的项目类型和数量被称为控件的“内容模型”。 有些控件只能包含一个项目和内容类型;例如,TextBox 的内容为字符串值,该值被分配给 Text 属性。 下面的示例设置 TextBox 的内容。
下图演示了结果。
但是,其他控件可以包含多个具有不同内容类型的项目;Button 的内容(由 Content 属性指定)可以包含各种项目,包括布局控件、文本、图像和形状。 下面的示例演示 Button,其内容包括 DockPanel、Label、Border 和 MediaElement。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.ButtonContentWindow" Title="Button Content"> ... <Button Margin="20"> <!-- Button Content --> <DockPanel Width="200" Height="180"> <Label DockPanel.Dock="Top" HorizontalAlignment="Center">Click Me!</Label> <Border Background="Black" BorderBrush="Yellow" BorderThickness="2" CornerRadius="2" Margin="5"> <MediaElement Source="media/wpf.wmv" Stretch="Fill" /> </Border> </DockPanel> </Button> ... </Window>
下图演示了此按钮的内容。
有关各种控件支持的内容类型的更多信息,请参见 WPF 内容模型。
触发器
尽管 XAML 标记的主要目的是实现应用程序的外观,但您也可以使用 XAML 实现应用程序行为的某些方面。 一个示例就是使用触发器根据用户交互更改应用程序的外观。 有关更多信息,请参见样式设置和模板化中的“触发器”。
控件模板
WPF 控件的默认 UI 通常由其他控件和形状构造而来。 例如,一个 Button 由 ButtonChrome 和 ContentPresenter 控件组成。 ButtonChrome 提供标准按钮外观,而 ContentPresenter 显示按钮的内容(由 Content 属性指定)。
有时控件的默认外观可能与应用程序的整体外观不一致。 在这种情况下,您可以使用 ControlTemplate 更改控件的 UI 的外观,而无需更改控件的内容和行为。
例如,下面的示例演示如何使用 ControlTemplate 更改 Button 的外观。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.ControlTemplateButtonWindow" Title="Button with Control Template" Height="158" Width="290"> <!-- Button using an ellipse --> <Button Content="Click Me!" Click="button_Click"> <Button.Template> <ControlTemplate TargetType="{x:Type Button}"> <Grid Margin="5"> <Ellipse Stroke="DarkBlue" StrokeThickness="2"> <Ellipse.Fill> <RadialGradientBrush Center="0.3,0.2" RadiusX="0.5" RadiusY="0.5"> <GradientStop Color="Azure" Offset="0.1" /> <GradientStop Color="CornflowerBlue" Offset="1.1" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse> <ContentPresenter Name="content" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> </ControlTemplate> </Button.Template> </Button> </Window>
Imports System.Windows ' Window, RoutedEventArgs, MessageBox Namespace SDKSample Public Class ControlTemplateButtonWindow Inherits Window Public Sub New() InitializeComponent() End Sub Private Sub button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) MessageBox.Show("Hello, Windows Presentation Foundation!") End Sub End Class End Namespace
using System.Windows; // Window, RoutedEventArgs, MessageBox namespace SDKSample { public partial class ControlTemplateButtonWindow : Window { public ControlTemplateButtonWindow() { InitializeComponent(); } void button_Click(object sender, RoutedEventArgs e) { // Show message box when button is clicked MessageBox.Show("Hello, Windows Presentation Foundation!"); } } }
在此示例中,默认按钮 UI 被替换为 Ellipse,后者具有深蓝色的边框并使用 RadialGradientBrush 进行填充。 ContentPresenter 控件显示 Button 的内容,即“Click Me!”。单击 Button 时,仍会作为 Button 控件的部分默认行为引发 Click 事件。 下图演示了结果。
有关更多信息,请参见 ControlTemplate。 有关介绍性示例,请参见 Styling with ControlTemplates Sample(使用 ControlTemplates 设置样式的示例)。
数据模板
控件模板使您可以指定控件的外观,数据模板则允许您指定控件内容的外观。 数据模板通常用于改进绑定数据的显示方式。 下图演示 ListBox 的默认外观,它被绑定到一个 Task 对象集合,该集合中的每个任务都有一个名称、说明和优先级别。
默认外观是您希望 ListBox 具有的外观。 但是,每个任务的默认外观只包含任务名称。 若要显示任务名称、说明和优先级别,必须使用 DataTemplate 更改 ListBox 控件的绑定列表项的默认外观。 下面的 XAML 定义了这样一个 DataTemplate,它通过使用 ItemTemplate 特性应用于每个任务。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.DataTemplateWindow" Title="With a Data Template"> ... <Window.Resources> <!-- Data Template (applied to each bound task item in the task collection) --> <DataTemplate x:Key="myTaskTemplate"> <Border Name="border" BorderBrush="DarkSlateBlue" BorderThickness="2" CornerRadius="2" Padding="5" Margin="5"> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Padding="0,0,5,0" Text="Task Name:"/> <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=TaskName}"/> <TextBlock Grid.Row="1" Grid.Column="0" Padding="0,0,5,0" Text="Description:"/> <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=Description}"/> <TextBlock Grid.Row="2" Grid.Column="0" Padding="0,0,5,0" Text="Priority:"/> <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=Priority}"/> </Grid> </Border> </DataTemplate> </Window.Resources> ... <!-- UI --> <DockPanel> <!-- Title --> <Label DockPanel.Dock="Top" FontSize="18" Margin="5" Content="My Task List:"/> <!-- Data template is specified by the ItemTemplate attribute --> <ListBox ItemsSource="{Binding}" ItemTemplate="{StaticResource myTaskTemplate}" HorizontalContentAlignment="Stretch" IsSynchronizedWithCurrentItem="True" Margin="5,0,5,5" /> </DockPanel> ... </Window>
下图演示了此代码的效果。
请注意,ListBox 保留其行为和整体外观;只有列表框显示的内容的外观发生了变化。
有关更多信息,请参见数据模板化概述。 有关介绍性示例,请参见 Introduction to Data Templating Sample(数据模板化简介示例)。
样式
开发人员和设计人员使用样式可以对其产品的特定外观进行标准化处理。 WPF 提供了一个强大的样式模型,其基础是 Style 元素。 下面的示例创建一个样式,该样式将窗口中的每个 Button 的背景色设置为 Orange。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.StyleWindow" Title="Styles"> ... <!-- Style that will be applied to all buttons --> <Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="Orange" /> <Setter Property="BorderBrush" Value="Crimson" /> <Setter Property="FontSize" Value="20" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="Margin" Value="5" /> </Style> ... <!-- This button will have the style applied to it --> <Button>Click Me!</Button> <!-- This label will not have the style applied to it --> <Label>Don't Click Me!</Label> <!-- This button will have the style applied to it --> <Button>Click Me!</Button> ... </Window>
由于此样式针对所有 Button 控件,因此它自动应用于窗口中的所有按钮,如下图所示。
有关更多信息,请参见样式设置和模板化。 有关介绍性示例,请参见 Introduction to Styling and Templating Sample(样式设置和模板化示例简介)。
资源
一个应用程序中的各控件应共享相同的外观,包括从字体和背景色到控件模板、数据模板和样式的所有方面。 您可以使用 WPF 对用户界面 (UI) 资源的支持将这些资源封装到一个位置,以便于重复使用。
下面的示例定义一个通用的由 Button 和 Label 共享的背景色。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.ResourcesWindow" Title="Resources Window"> <!-- Define window-scoped background color resource --> <Window.Resources> <SolidColorBrush x:Key="defaultBackground" Color="Red" /> </Window.Resources> ... <!-- Button background is defined by window-scoped resource --> <Button Background="{StaticResource defaultBackground}">One Button</Button> <!-- Label background is defined by window-scoped resource --> <Label Background="{StaticResource defaultBackground}">One Label</Label> ... </Window>
此示例使用 Window.Resources 属性元素实现背景色资源。 此资源可用于 Window 的所有子项。 资源范围有多种,包括下面按解析顺序列出的范围:
-
单个控件(使用继承的 FrameworkElement.Resources 属性)。
-
Window 或 Page(也使用继承的 FrameworkElement.Resources 属性)。
-
Application (使用 Application.Resources 属性)。
范围的多样性使您可以灵活选择定义和共享资源的方式。
作为将资源与特定范围直接关联的一个备用方法,您可以使用单独的 ResourceDictionary(可以在应用程序的其他部分引用)打包一个或多个资源。 例如,下面的示例在资源字典中定义默认背景色。
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!-- Define background color resource --> <SolidColorBrush x:Key="defaultBackground" Color="Red" /> <!-- Define other resources --> ... </ResourceDictionary>
下面的示例引用上一个示例中定义的资源字典,从而在应用程序中共享。
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.App"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="BackgroundColorResources.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> ... </Application>
资源和资源字典是 WPF 支持主题和外观的基础。
参见XAML 资源。
主题和外观
从视觉的角度上讲,主题定义 Windows 以及在其中运行的应用程序的全局外观。 Windows 附带了几个主题。 例如,Microsoft Windows XP 附带了 Windows XP 和 Windows 经典主题,而 Windows Vista 附带了 Windows Vista 和 Windows 经典主题。 由主题定义的外观可定义 WPF 应用程序的默认外观。 但是,WPF 并未与 Windows 主题直接集成。由于 WPF 的外观由模板定义,因此 WPF 为每个已知 Windows 主题包括了一个模板,这些主题包括 Aero (Windows Vista)、Classic (Microsoft Windows 2000)、Luna (Microsoft Windows XP) 和 Royale (Microsoft Windows XP Media Center Edition 2005)。这些主题作为资源字典进行打包,如果未在应用程序中找到资源,则可以解析这些资源字典。许多应用程序依赖于这些主题来定义其视觉外观;与 Windows 外观保持一致有助于用户更轻松地熟悉更多应用程序。
另一方面,某些应用程序的用户体验不一定来自标准主题。 例如,Microsoft Windows Media Player 通过音频和视频数据进行操作,并受益于不同风格的用户体验。 此类 UI 可以提供自定义的、应用程序特定的主题。 这些主题称为外观,带有外观的应用程序通常提供挂钩,用户可以通过这些挂钩自定义外观的各个方面。Microsoft Windows Media Player 具有多个预制的外观以及大量第三方外观。
WPF 中的主题和外观都可以使用资源字典非常轻松地进行定义。 下面的示例演示示例外观定义。
<!-- Blue Skin --> <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SDKSample"> <Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="Blue" /> </Style> ... </ResourceDictionary>
<!-- Yellow Skin --> <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:SDKSample"> <Style TargetType="{x:Type Button}"> <Setter Property="Background" Value="Yellow" /> </Style> ... </ResourceDictionary>
有关更多信息,请参见样式设置和模板化中的“共享的资源和主题”。
自定义控件
尽管 WPF 提供了大量自定义项支持,您仍然可能会遇到现有 WPF 控件不能满足应用程序或用户需求的情况。 在以下情况下可能会出现这种情形:
-
无法通过自定义现有 WPF 实现的外观来创建您需要的 UI。
-
现有 WPF 实现不支持(或很难支持)您需要的行为。
但是,目前您可以利用三个 WPF 模型之一创建一个新的控件。 每个模型都针对一个特定的方案,并要求您的自定义控件从特定的 WPF 基类派生而来。 此处列出了此三个模型:
-
用户控件模型。 从 UserControl 派生的自定义控件,由其他一个或多个控件组成。
-
控制模型。 从 Control 派生的自定义控件,用于生成使用模板将其行为和外观相分离的实现,与多数 WPF 控件非常相似。 从 Control 派生,与用户控件相比,您可以更自由地创建自定义 UI,但可能需要投入更多精力。
-
框架元素模型。 从 FrameworkElement 派生的自定义控件,其外观由自定义呈现逻辑(而不是模板)定义。
下面的示例演示从 UserControl 派生的自定义数值 up/down 控件。
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.NumericUpDown"> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <!-- Value text box --> <Border BorderThickness="1" BorderBrush="Gray" Margin="2" Grid.RowSpan="2" VerticalAlignment="Center" HorizontalAlignment="Stretch"> <TextBlock Name="valueText" Width="60" TextAlignment="Right" Padding="5"/> </Border> <!-- Up/Down buttons --> <RepeatButton Name="upButton" Click="upButton_Click" Grid.Column="1" Grid.Row="0">Up</RepeatButton> <RepeatButton Name="downButton" Click="downButton_Click" Grid.Column="1" Grid.Row="1">Down</RepeatButton> </Grid> </UserControl>
imports System 'EventArgs imports System.Windows 'DependencyObject, DependencyPropertyChangedEventArgs, ' FrameworkPropertyMetadata, PropertyChangedCallback, ' RoutedPropertyChangedEventArgs imports System.Windows.Controls 'UserControl Namespace SDKSample ' Interaction logic for NumericUpDown.xaml Partial Public Class NumericUpDown Inherits System.Windows.Controls.UserControl 'NumericUpDown user control implementation ... End Class End Namespace
using System; // EventArgs using System.Windows; // DependencyObject, DependencyPropertyChangedEventArgs, // FrameworkPropertyMetadata, PropertyChangedCallback, // RoutedPropertyChangedEventArgs using System.Windows.Controls; // UserControl namespace SDKSample { public partial class NumericUpDown : UserControl { // NumericUpDown user control implementation ... } }
下一个示例演示将用户控件与 Window 合并所需的 XAML。
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SDKSample.UserControlWindow" xmlns:local="clr-namespace:SDKSample" Title="User Control Window"> ... <!-- Numeric Up/Down user control --> <local:NumericUpDown /> ... </Window>
下图演示 Window 中承载的 NumericUpDown 控件。
有关自定义控件的更多信息,请参见控件创作概述。
本文中提到了以下概述和示例。
概述
示例
3-D Solids Sample(三维实体示例) Animation Example Gallery(动画示例库) Brushes Sample(画笔示例) Data Binding Demo(数据绑定演示) Geometries Sample(几何图形示例) |
Introduction to Data Templating Sample(数据模板化简介示例) Introduction to Styling and Templating Sample(样式和模板化简介示例) Shape Elements Sample(Shape 元素示例) Styling with ControlTemplates Sample(使用 ControlTemplates 设置样式的示例) WPF Layout Gallery Sample(WPF 布局库示例) |