Windows Presentation Foundation (简称WPF),是一个可创建适用于Windows的桌面客户端应用程序的UI框架。WPF框架支持广泛的应用程序开发功能,包括应用程序模型、空间、图形和数据绑定。WPF使用Extension Application Markup Language(XAML)为应用程序编程提供声明性模型。
WPF有两种实现:
1、托管在GitHub上的开放源代码实现。此版本在.NET core 3.0上运行。适用于XAML的WPF视觉对象设计器最低要求为VS2019版本的16.3。
2、受VS2019和VS2017支持的.NET Framework实现。
本系列文章适用于.NET Core 3.0和WPF。
一、XAML
XAML是一种基于XML的生命语言,WPF用它来定义资源或UI元素等内容。XAML中定义的元素表示程序集中对象的实例化,XAML与大多数其他标记语言不同,后者在运行时解释,且与后备类型系统无直接关系。
下面演示如何创建UI中的按钮,其中Button是类型,Content是属性:
<StackPanel> <Button Content="Click Me!" /> </StackPanel>
XAML扩展
XAML为标记扩展提供了语法。标记扩展可用于特性形式、属性元素或同时采用这两种形式来提供属性的值。
例如,上述XAML定义了一个按钮,其中可以设置内容为文本字符串“Click Me!”,但该内容可以改变由受支持的标记扩展进行设置。标记扩展是通过一个大括号{}来定义的。然后紧跟在大括号后面的字符串标记来标识标记扩展的类型:
<StackPanel> <Button Content="{MarkupType}" /> </StackPanel>
WPF为XAML提供了不同的标记扩展,例如用于数据绑定的{Binding}。
二、属性系统
WPF提供一组服务,这些服务可用于扩展类型的属性的功能。这些服务统称为WPF属性系统。由WPF属性系统支持的属性称为依赖属性。
依赖属性,通过提供支持属性的DependencyProperty类型来扩展属性功能。依赖属性类型是使用专用字段支持属性的标准模式的替代实现。
依赖属性
在WPF中,依赖属性通常公开为标准.NET属性。在基本级别,可以直接与这些属性交互。依赖属性的用途在于提供一种方法来基于其他输入的值计算属性值。这些其他输入可能包括系统属性(如主题和用户首选项)或者来自数据绑定和动画的实时属性。
可以实现依赖属性来提供验证、默认值以及监视对其他属性的更改的回调。派生类还可以通过重写依赖属性元数据(而不是新建属性或重写现有属性)来更改现有属性的某些具体特征。
依赖对象
WPF属性系统另外一个重要对象是DependencyObject。此类型定义可以注册和拥有依赖属性的基类。GetValue和SetValue方法为依赖对象实例提供了依赖属性的支持实现。
下面示例演示的依赖对象定义一个名为ValueProperty的单一依赖属性标识符。此依赖属性通过使用Value .NET属性创建而成:
public class TextField: DependencyObject { public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(TextField), new PropertyMetadata("")); public string Value { get { return (string)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } }
此依赖属性被定义为依赖对象类型(TextField)的静态成员。此依赖属性必须通过依赖对象注册。
上例中的Value属性包装此依赖属性,从而提供了可能让你感觉熟悉的标准.NET属性模式。
三、事件
WPF提供了一个事件系统,它是在您熟悉的.net公共语言运行时(CLR)事件之上分层的。这些WPF事件称为路由事件。
路由事件是一个CLR事件,它由一个RoutedEvent类的实例支持,并在WPF事件系统中注册。从事件注册中获得的RoutedEvent实例通常作为注册类的公共静态只读(public static readonly)字段成员保留,因此它拥有路由事件。连接到相同名称的CLR事件(有时称为包装器事件)是通过覆盖CLR事件的 add 和 remove 实现来完成的。路由事件的支持和连接机制在概念上类似于依赖属性是由DependencyProperty类支持并注册到WPF属性系统的CLR属性。
路由事件系统的主要优点是,事件在寻找处理程序的控制元素树中冒泡(The main advantage of the routed event system is that events are bubbled up the control element tree looking for a handler.)。例如,因为WPF具有丰富的内容模型,所以您可以将图像控件设置为按钮控件的内容。当在图像控件上单击鼠标时,您可能希望它使用鼠标事件,从而中断导致按钮调用Click事件的hit-tests。在传统的CLR事件模型中,您可以通过将相同的处理程序附加到图像和按钮来解决这个限制。但是使用路由事件系统,在图像控件上调用的鼠标事件(比如选择它)会向上冒泡到父按钮控件。
四、数据绑定
WPF数据绑定为应用程序呈现数据并与数据交互提供了一种简单且一致的方式。
元素能够以公共语言运行时(CLR)对象和XML的形式,绑定到不同类型数据源中的数据。WPF还提供了通过拖放操作传输数据的机制。
数据绑定是在应用程序UI和业务逻辑之间建立连接的过程。如果绑定了具有正确的设置,并且数据提供适当的通知,则在数据更改其值时,绑定到该数据的元素会自动反应更改。数据绑定还意味着,如果元素中数据的外部表示形式放生更改,则基础数据会自动进行更新以反应更改。例如,如果用户编辑TextBox元素中的值,则基础数据值会自动更新以反映该更改。
数据绑定可以通过{Binding}标记扩展来配置。以下示例演示绑定到数据对象的ButtonText属性。如果绑定失败,则会使用Click Me!的值。
<StackPanel> <Button Content="{Binding ButtonText, FallbackValue='Click Me!'}" /> </StackPanel>
五、UI组件
WPF 提供许多几乎在所有 Windows 应用程序中都会使用的常见 UI 组件,如Button
、Label
、TextBox
、Menu
和 ListBox
。 以前,这些对象称为控件。 虽然 WPF SDK 继续使用术语“控件”泛指任何代表应用程序中可见对象的类,但请务必注意,类不必从 Control
类继承即可具有可见外观。 从 Control
类继承的类包含一个 ControlTemplate
,它允许控件的使用方在无需创建新子类的情况下从根本上改变控件的外观。
六、样式和模板
WPF样式设置和模板化是指一套功能(样式、模板、触发器和情节提要),可使应用程序、文档和UI设计者创建极具视觉表现力的应用程序,并为其产品创建标准化的特定外观。
WPF样式模型的另一个功能是内容的呈现和逻辑的分离。这意味着,设计人员可以使用XAML来处理应用的外观,而开发人员可以在其他位置处理逻辑编程。
另外,了解资源很重要,正是这些资源使得样式和模板能够重复使用。
七、资源
WPF资源是可以在应用程序中的不同位置重复使用的对象。资源示例包括样式、模板和颜色画笔。可以采用代码和XAML格式定义和引用资源。
每个框架级别元素(FrameworkElement 或 FrameworkContentElement )都具有Resource 属性。该属性是包含已定义资源的ResourceDictionary类型。由于所有元素都继承自框架级元素,因此所有元素可都可以定义资源。最常见的做法是:在XAML文档的根元素上定义资源。