C# 中的 WPF

2025年3月17日 | 阅读 24 分钟

WPF 称为 Windows Presentation Foundation。Windows Presentation Foundation 称为开发框架。WPF 也称为 .Net 框架的子系统。Windows Presentation Foundation 框架可以构建 Windows 客户端应用程序。Windows 应用程序可以在 Windows 操作系统上运行。我们使用 XAML 语言作为前端,C# 语言作为后端。

.NET 框架中,WPF 作为 Windows 库存在。Windows 客户端应用程序可以通过 Windows 库构建。Windows 库还可以用于生成下一代 Windows Form。目前,我们使用的是 WPF 的 4.5 版本。我们也可以将 WPF 称为引擎。通过使用 Windows Presentation Foundation,我们可以创建、显示和操作 Windows 7 和 Windows 操作系统中的用户界面 (UI)、文档、电影、图像和媒体。WPF 包含一套库。WPF 的库提供了功能,通过这些功能我们可以构建、运行、执行,并通过 WPF 库,我们可以管理所有 Windows 客户端应用程序。

WPF 使用 XAML,这是一种基于 XML 的语言。 XML 用于定义和链接各种元素。使用 WPF 开发的应用程序,我们可以将它们部署为独立的桌面程序,或者将 WPF 应用程序作为嵌入式对象托管在 网站上。

WPF 应用程序旨在统一用户界面元素。所有这些都包括固定和自适应文档、2D/3D 渲染、运行时动画、预渲染媒体。WPF 运行时库包含 Microsoft Windows 的所有版本。

Microsoft Silverlight 提供的功能是 WPF 的子集,它提供嵌入式 Web 控件,相比于 Adobe Flash。

C# 中 WPF 的特性

  • Windows Presentation Foundation 是一个图形系统。WPF 为我们提供了构建下一代 Windows 应用程序的功能。
  • WPF 结合了用户界面 2D、3D 图形、文档和多媒体的功能。
  • WPF 也称为 API,通过它可以大规模构建具有出色用户体验的 Windows 客户端应用程序。
  • Windows Presentation Foundation 包含了所有能够超越 MFC、Windows Forms(包括 GDI、GDI+HTML 等)的技术的能力。

WPF 的特性如下

1. Direct3D

图形包括桌面项目,如窗口。图形使用 Direct3D 渲染。通过它,我们可以显示复杂的图形和自定义主题。使用 Direct3D,我们可以将图形任务卸载到 Windows 中的 GPU。使用 Direct3D 减少了 CPU 的工作负载。我们优化 GPU 进行并行像素计算。通过使用 WPF 的 Direct3D 功能,屏幕可以轻松刷新,并可以在不需要强大 GPU 的市场(如上网本市场)中降低兼容性。

Windows Presentation Foundation 是 Microsoft 的 UI 框架,用于创建具有丰富用户体验的应用程序。WPF 的重点主要在于矢量图形,我们允许控件和元素在不损失质量或像素化的情况下进行缩放。

2. XAML

XAML 语言的使用是 WPF 的一个特性。XAML 也称为基于 XML 的语言。XAML 在 WPF 中的目的是设计表示逻辑。XAML 启用了编程模型。使用 XAML,我们可以分离表示逻辑和业务逻辑。在应用程序设计完成后,我们可以将其移交给开发人员进行应用程序的集成和业务逻辑。这种方法比代码更具可读性,并且更简短。

3. 控件集

WPF 包含大量控件集,通过这些控件集我们可以实现用户界面的快速组装。丰富的控件集也是 WPF 的一个特性。大多数控件与 Windows Forms 控件相似,但在控件上有一些小的变化。

  • 列表框

Windows Forms 中的 Listbox 仅包含文本值。在 ListBox 中,我们无法显示带文本的图像列表。

ListBox 示例

C# 和 WPF 中的 ListBox 类显示 Listbox 控件。WPF 中的 ListBox 包含 ListBox 中的项目集合。在这里,我们将展示如何向 Listbox 添加项目、从 Listbox 中删除项目以及将 Listbox 绑定到数据源。

高度和宽度属性将显示 Listbox 的宽度和高度。ListBox 的 Name 属性将显示控件的名称。Name 称为唯一标识符。ListBox 的 Margin 属性显示 Listbox 在父控件上的边距。HorizontalAlignment 和 VerticalAlignment 属性用于设置水平和垂直对齐。

下面的代码用于设置 ListBox 控件的名称、高度和宽度。

在这里,我们将对 Listbox 执行不同的功能。

静态向 ListBox 控件添加项

ListBox 控件是 ListBox 项的集合。要向 ListBox 控件添加项,我们将编写以下代码

要在 WPF 的 ListBox 控件中添加项,我们将遵循以下步骤

对于 WPF 应用程序,请单击 文件->新建->项目,如下图所示

WPF Tutorial

在此之后,将出现下图所示的窗口

WPF Tutorial

根据上图,单击 **Visual C#->WPF App (.NET Framework)->应用名称 (WPF_App1)->单击“确定”。**

在此之后,将出现下图所示的窗口

WPF Tutorial

要静态添加 ListBox 控件,我们将在 MainWindow.XAML 窗口中编写以下代码

上述代码的设计如下图所示

WPF Tutorial

在上面的代码中,我们在设计时从 XAML 向 ListBox 添加了项。

输出

WPF Tutorial

4. 独立屏幕分辨率

独立屏幕分辨率是屏幕分辨率的一个清晰特性。在独立屏幕的形式下,WPF 的用户界面即使在低分辨率屏幕上看起来也会更好。对于独立屏幕分辨率,屏幕分辨率使用 DirectX 组件,而 Windows Form 应用程序使用机器的 32 个组件。为了与 DirectX 组件通信,WPF 使用媒体集成层 (MIL)。直接组件将在 WPF 的用户界面上显示矢量图形。

借助下图,我们可以轻松找出 Windows Forms UI 和 WPF UI 在低分辨率屏幕上的差异。

WPF Tutorial

在上图的“W”字符处,在较低分辨率下,我们发现 Windows Forms 看起来像是失真的图像,而基于矢量的 WPF 看起来优雅。

5. 控件内的控件

在 WPF 中,除了文本,我们还可以将控件定义为另一个基本控件的内容。例如:像按钮一样。WPF 的这一特性对开发人员来说确实是一个惊人的事实,通过它我们可以了解 WPF 在用户界面方面的强大功能。

这是 Window 中控件内的控件的 XAML 代码

输出

WPF Tutorial

6. 控件模板

如果我们想使用 WPF 更改按钮的形状,我们可以更改按钮的形状。这里我们将以 WPF 为例,声明一个按钮并将其形状更改为椭圆形。

输出

WPF Tutorial

7. 动画

WPF 支持动画,这是基于时间的,而不是基于帧的方法。这会将系统速度与系统性能分离开来。WPF 通过计时器支持低级动画,并通过动画类支持高级抽象。

  • 我们可以动画任何 WPF 元素的属性,只要我们将其注册为依赖属性。
  • 我们可以根据要动画的属性的 .NET 类型来动画类。ColorAnimation 类可以更改元素的颜色,而 DoubleAnimation 类可以用来动画元素的宽度。
  • Storyboards 可以包含动画组。
    • 为了操作动画,Storyboards 是启动、停止和暂停的主要方式。
    • 我们可以通过外部事件(包括用户操作)来触发动画。
    • 为了重绘,场景是时间触发的。

8. 文档

WPF 支持文档分页。WPF 的 DocumentViewer 类用于读取固定布局的文档。页面视图由 FlowDocumentReader 类显示,通过它我们可以看到滚动、每页和文本流等不同模式的视图,在调整查看区域大小时。

WPF 为我们提供了 XML 纸张规范文档。它还支持使用 Open Packaging Conventions 读取和写入分页文档。

9. 互操作性

可以使用 **ElementHost** 和 **WindowsFormsHost** 类与 Windows Forms 结合使用。

要使用 Windows Form,我们将执行以下 WPF C# 代码

10. 各种布局的可用性

我们使用布局来在用户界面上逻辑地分隔控件。使用布局,我们可以清晰地在窗口上显示控件。WPF 中有一套强大的布局控件。

WPF 中的布局有

1. Stack Panel: StackPanel 是 WPF 中简单且有用的布局面板。StackPanel 以堆叠的形式包含元素,元素可以排列在彼此的下方或旁边,元素的堆叠取决于方向。StackPanel 用于创建任何类型的列表。为了使用内部布局面板,我们使用了 WPF 项控件,如 ListBox、Combo Box 或 Menu。

输出

WPF Tutorial

水平排列堆叠项。

为了在 Stack Panel 中水平排列项目,我们将以对话窗口的两个按钮“确定”和“取消”为例,因为文本的大小可能会改变(如果用户更改字体大小或切换语言),我们应该避免固定大小的按钮,两个按钮都取决于它们的大小。如果按钮需要空间,它们会自动获得。

WPF Tutorial

2. Grid 布局

Grid 是一个布局面板;借助 Grid Layout,我们可以将子控件排列在表格结构中,该结构包含行和列。Grid 布局的工作方式类似于 HTML 表格,但布局更灵活。一个单元格可以包含多个控件。控件可以跨越多个单元格并相互重叠。

控件可以通过 HorizontalAlignment 和 VerticalAlignment 属性自行调整大小,这些属性由锚点定义。锚点与网格线的距离由控件的边距定义。

定义行和列

默认情况下,Grid 包含一行一列。我们将 RowDefinition 项添加到 RowDefinition 的集合中,并将 ColumnDefinition 项添加到 ColumnDefinition 的集合中。

这里我们以一个显示三行两列的网格为例

大小可以定义为逻辑单位的绝对数量,也可以定义为百分比值或逻辑单位

固定:固定显示逻辑单位(1/96 单位)的固定大小。

自动:自动,它占用控件所需的空间。

星号(*):这将占用可用空间。

Grid 被认为是 WPF 中强大且有用的布局。在 Grid 中,我们必须将子元素安排在行和列的单元格中。当添加 XAML 文档或在 Visual Studio 中创建新的 WPF 项目时,Visual Studio 会自动将 Grid 作为窗口元素中的第一个容器。

我们可以通过两种方式创建行和列

第一种方法:通过 XAML 代码

默认情况下,Grid 包含一行的内容和一列的内容。我们可以使用 RowDefinition 元素在 Grid.RowDefinition 属性中为每一行添加更多的行,并使用 ColumnDefinition 元素在 Grid.ColumnDefinition 属性中为列元素添加更多的列。Grid 是不可见的。为了显示 GridLines,我们将 ShowGridLines 属性设置为 true。GridLines 有助于调试,以确定元素位于哪个单元格中。

这里我们举一个例子,创建 3 行 3 列。现在我们可以添加 9 个 TextBlock 并通过定义 Grid.Row 和 Grid.Column 的值来维护 TextBlock 在 Grid 中的位置。如果未定义 Grid.Row 和 Grid.Column 属性,则在这种情况下,我们可以将元素放置在 Grid.Row="0" 和 Grid.Column="0"。换句话说,我们可以将元素放置在第一行第一列。

为了显示网格中的行和列,我们将编写以下代码

输出

WPF Tutorial

将控件添加到 Grid

要将控件添加到 Grid Layout,我们只需将声明放在 Grid 的开始和结束标签之间。

行和列定义必须在子控件定义之前。

Grid Layout 面板为我们提供了两个附加属性 Grid.Column 和 Grid.Row。这两个属性定义了控件的位置。

要在 WPF 中将控件添加到 Grid,我们将编写以下代码

输出

WPF Tutorial

3. Dock Panel

DockPanel 用于定义我们可以相互排列元素的区域。我们可以水平或垂直排列元素。使用 Dock Panel,我们可以轻松地使用 Dock 属性将子元素停靠在顶部、底部、右侧、左侧以及中心。元素的停靠侧由附加属性 **DockPanel.Dock** 定义。LastChildFill 属性必须设置为 true。

使用 **LastChildFill** 属性,它将填充最后一个子元素的剩余空间。分层 Dock Panel 类如下所示

WPF Tutorial

要设置每个侧面的停靠元素,我们将为此编写以下代码

输出

WPF Tutorial

DockPanel 的属性

这里是我们最常用的 Dock 属性。这是 DockPanel 属性列表

序号属性描述
1.背景Background 属性用于获取或设置将填充 Panel 内容区域的画笔。此属性继承自 Panel。
2.儿童Children 属性用于获取此 Panel 的子元素的 UIElement 集合。Children 也继承自 Panel。
3.底座借助 Dock 属性,我们可以获取或设置一个值,该值显示子元素在父 Dock Panel 中的位置。
4.高度使用此属性,我们可以获取或设置元素的高度。Height 属性继承自 FrameworkElement。
5.ItemWidth使用此属性,我们可以获取或设置一个值,通过该值指定 WrapPanel 包含的所有项的宽度。
6.LastChildFill使用此属性,我们可以获取或设置一个值,该值表示 DockPanel 中的最后一个子元素会拉伸以填充剩余的可用空间。
7.LogicalChilderen通过此属性,我们可以获取一个枚举器,它可以迭代此 Panel 的逻辑子元素。此属性继承自 Panel。
8.LogicalOrientation此属性有助于在 Panel 只支持一维布局的情况下进行方向设置。LogicalOrientaton 属性继承自 Panel。
9.边距Margin 属性将获取或设置元素的外部边距。
10.名称Name 属性获取或设置元素的名称以供识别。Name 在代码隐藏(如事件处理代码)中提供了引用。我们可以在 XAML 处理器处理过程中,在构造完成后引用它到标记元素。Name 属性继承自 FrameworkElement。
11.导向使用此属性,我们可以获取或设置用于指定子元素内容排列维度的值。
12.ParentParent 属性将获取元素的逻辑父元素。Parent 继承自 FrameworkElement。
13.资源此属性获取或设置本地定义的元素。Resource 属性继承自 FrameworkElement。
14.风格Style 属性获取或设置元素在渲染时使用的样式。Style 属性继承自 FrameworkElement。

Dock Panel 最常用的方法

这是 DockPanel 最常用的方法

序号。方法描述
1.GetDockGetDock 方法 **获取** 特定 UI 元素的 Dock 附加属性的值。
2.SetDockSetDock 方法 **设置** Dock 附加属性的值到特定元素。

这里我们将举例说明如何向 DockPanel 添加子元素。

为此,我们将使用 XAML 示例来创建一个面板内的按钮。

示例

MainWindow.XAML

XAML 代码在 C# 中的实现如下

单击任何按钮后,它将显示消息。这里我们将举例说明当我们单击任何按钮时,单击中心按钮,它会显示消息,如下所示

输出

WPF Tutorial

3. Canvas Panel

Canvas 是 WPF 中最基本的布局面板。Canvas Layout 允许我们使用坐标来排列子元素,这与 Windows Forms Application 非常相似。借助 Canvas,我们可以指定与任何角落相关的坐标。我们可以使用附加属性(Top、Bottom、Left 和 Right)来调整 Canvas 内子元素的位置。

Canvas 是一个轻量级的容器。当我们在运行时调整窗口大小时,我们无法调整 Canvas 的子元素大小,这使得它在创建表单时不太有用。Canvas 在需要处理图形的情况下很有用。

该 Panel 用于组合 2D 图形(如椭圆、矩形)元素。它不用于布局用户界面元素。

Canvas panel 的分层继承如下所示

WPF Tutorial

Canvas 类最常用的属性如下所示

序号属性描述
1.背景我们使用 Background 属性获取或设置画笔,并可以填充 Panel 的内容区域。Background 继承自 Panel。
2.ZIndexProperty此属性用于识别 **Canvas.ZIndex** XAML 附加属性。
3.资源要获取或设置本地资源,我们使用 Resources 属性。Resource 属性继承自 **FrameworkElement**。
4.ParentParent 属性用于获取逻辑父元素。Parent 属性继承自 **FrameworkElement**。

Canvas 的方法

Canvas 最常用的方法如下所示

序号。方法描述
1.GetLeftGetLeft 方法用于获取 XAML 的 Canvas.Left 附加属性的值。
2.GetTopGetTop 方法用于获取 XAML 的 Canvas.Top 附加属性的值。此方法用于目标元素。
3.GetZIndexGetZIndex 方法用于获取 Canvas.ZIndex 的值。此方法是 XAML 的附加属性,用于目标元素。
4.SetLeftSetLeft 方法用于设置 Canvas.Left 的值。对于目标元素,我们使用了 XAML 属性。
5.SetTop要设置和获取 Canvas.Top 的值,我们使用 SetTop 方法。我们使用 XAML 附加属性作为目标元素。
6.SetZIndex要设置和获取 Canvas.ZIndex 的值,我们使用 SetZindex 方法。XAML 附加属性用于目标元素。

示例:这里我们有一个示例,说明如何将子元素添加到 Canvas。这里我们将编写一个代码,在 Canvas 中创建一个具有不同偏移量的椭圆

MainWindow.XAML

输出

WPF Tutorial

用于定位的 Canvas 属性

  • Top:此属性用于获取或设置一个值,该值表示元素顶部与其父 Canvas 顶部之间的距离。
  • Left:此属性用于获取或设置一个值,该值表示元素左侧与其父 Canvas 左侧之间的距离。
  • Right:此属性用于获取或设置一个值,该值表示 Canvas 右侧与其父 Canvas 右侧之间的距离。
  • Bottom:此属性用于获取或设置一个值,该值表示元素顶部与其父 Canvas 顶部之间的距离。

Canvas 布局示例

Canvas 布局用于元素的正确位置、元素的对齐。如果我们不使用 Canvas 属性,元素就会重叠。

我们将在未使用 Canvas 属性的情况下举例说明。

现在输出将如下所示

输出

WPF Tutorial

分配 Canvas 属性后

对于绝对位置,我们大部分时间使用 Canvas 属性,如 **canvas.Top** 和 **Canvas.Left** 属性。

MainWindow.XAML

输出

WPF Tutorial

5. WPF Wrap Panel

WPF WrapPanel 控件是一个 Panel,它默认按顺序从左到右排列子元素。如果堆叠的子元素不适合当前所在的行或列,则剩余元素将以相同的顺序换行到剩余空间。

这里我们将举例说明两个 Wrap Panel,一个水平排列,另一个垂直排列。

XAML 中的 WrapPanel 元素显示 Wrap Panel WPF 控件。

这里我们有一个代码片段,它在 XAML 中声明了 **WrapPanel**,并设置了高度、宽度和背景属性。

下面是 Wrap Panel 的代码

输出

WPF Tutorial

6. WPF 中的 ViewBox

ViewBox 是 WPF 中一个有益的控件。ViewBox 会调整自身以适应可用空间。它不会调整内容大小,而是转换自身。ViewBox 是 WPF 控件的另一个标准。ViewBox 仅包含一个子控件。如果我们想向 ViewBox 添加更多子控件,它将报错。

ViewBox 元素在 XAML 中显示 WPF ViewBox 控件,如下所示

ViewBox 有一个 Stretch 属性,它显示内容如何适应空间,我们可以填写其值。

这里我们将举例说明。现在我们将创建一个名为 ViewBoxDemo 的新 WPF 应用程序。

输出

WPF Tutorial

WPF 中的数据绑定

数据绑定为我们提供了一种简单而强大的方法,可以自动更新业务模型和用户界面之间的数据。我们称这种机制为数据绑定。当我们更改业务模型的数据时,它将自动反映到用户界面,反之亦然。为了将数据带到用户界面,我们使用此方法。

数据绑定可以是单向的,可以从**源到目标,或者从目标到源**,或者是双向的,即**源到目标或目标到源**。

为了使数据绑定正常工作,我们必须在两边提供更改通知,这告诉我们何时更新**数据绑定**中的目标值。

在 .NET 属性中,我们通过引发 **INotifyPropertyChanged** 接口的 **PropertyChanged** 事件来进行数据绑定。通常,我们使用标记扩展在 XAML 中进行数据绑定。

数据绑定为我们提供了一种机制,该机制为 Windows Runtime 应用程序提供了一种简单易行的方法来显示数据交互。

通过数据绑定,我们可以实现 UI 元素和用户界面上的数据对象之间的数据流。当绑定完成并且数据或我们的业务模型之后发生更改时,它将自动反映到用户界面元素,反之亦然。

数据绑定有两种类型

  1. 单向数据绑定
  2. 双向数据绑定

单向数据绑定

在单向绑定中,我们可以将数据从源(源是保存数据的对象)绑定到目标(目标是我们可以看到数据的对象)。

为了理解单向绑定,我们将举以下例子

为了理解单向绑定,我们将创建一个名为 WPFData 的 WPF 项目。

为此,我们将编写 XAML 代码,在其中创建两个标签、两个文本框、一个按钮,并使用某些属性对其进行初始化。

MainWindow.XAML

MainWindow.XAML.cs

之后,我们可以轻松运行此应用程序,然后我们将看到 MainWindow 的输出。我们可以轻松绑定人的姓名和年龄。

输出

WPF Tutorial

单击“显示”按钮后,它会在消息框中显示姓名和年龄。

WPF Tutorial

在对话框中,我们可以修改人的姓名和年龄。

WPF Tutorial

但是,更新值后,我们将再次看到相同的消息。

WPF Tutorial

这是因为我们在 XAML 中将数据绑定模式设置为单向。如果我们想显示更新后的数据,我们需要理解双向数据绑定。

双向数据绑定

在双向数据绑定中,我们可以通过图形用户界面更新数据,并在源中获取更新后的数据。如果我们希望在查看时更改源并希望更新视图。

这里我们将举例说明如何通过 XAML 代码将绑定模式从单向更改为双向绑定

MainWindow.XAML

MainWindow.XAML.cs

当我们运行此应用程序时,它将显示如下所示的输出

输出

WPF Tutorial

单击“显示”按钮后,它会在对话框中显示消息。

WPF Tutorial

现在我们想通过用户界面更改姓名和年龄的值

WPF Tutorial

这将我们在对话框中显示更新后的值

WPF Tutorial

在上面的部分,我们已经描述了关于 WPF 的所有基本概念。


下一个主题WPF ListBox