本教程介绍如何使用 Visual Studio 创建新的 Windows Presentation Foundation (WPF) 应用。 使用 Visual Studio,可以向窗口添加控件以设计应用的 UI,并处理这些控件中的输入事件以与用户交互。 在本教程结束时,你有一个简单的应用,用于向列表框添加名称。
文章目录
前言
在本教程中,你将了解:
创建新的 WPF 应用。
向窗口添加控件。
处理控制事件以提供应用功能。
运行应用。
下面是在学习本教程时创建的应用的预览版:
一、先决条件
- Visual Studio 2022 版本 17.12 或更高版本
选择 .NET 桌面开发工作负载
选择 .NET 9 单个组件
二、创建 WPF 应用
创建新应用的第一步是打开 Visual Studio 并通过模板生成应用。
-
打开 Visual Studio。
-
选择“创建新项目”。
-
在“搜索模板”框中,键入“wpf”,然后按 Enter。
-
在“代码语言”下拉列表中,选择“C#”或“Visual Basic”。
-
在模板列表中,选择“WPF 应用程序”,然后选择“下一步”。
下图显示了 C# 和 Visual Basic .NET 项目模板。 如果应用 了代码语言 筛选器,则仅显示该语言的模板。
- 在“配置新项目”窗口中,执行以下操作:
在“项目名称”框中,输入“Names”。
选中“将解决方案和项目放在同一目录中”复选框。
(可选)选择其他位置以保存代码。
选择“下一步”按钮。
- 在“其他信息”窗口中,选择目标框架的 .NET 9.0(标准术语支持)。 选择“创建”按钮。
生成应用后,Visual Studio 应打开默认窗口 MainWindow 的 XAML 设计器窗口。 如果设计器不可见,请在解决方案资源管理器窗口中双击 MainWindow.xaml 文件以打开设计器。
三、Visual Studio 的重要部分
在 Visual Studio 中对 WPF 的支持有五个重要组件,可在创建应用时与之交互:
-
“解决方案资源管理器”
所有项目文件、代码、窗口、资源都在此窗口中显示。 -
属性
此窗口显示可以根据所选项配置的属性设置。 例如,如果从“解决方案资源管理器”中选择一个项,你会看到与该文件相关的属性设置。 如果在设计器中选择对象,你将看到元素的设置。 在上一张图像中,在设计器中选择了窗口的标题栏。 -
工具箱
工具箱包含可添加到设计图面的所有控件。 若要向当前图面添加控件,请双击控件或拖放该控件。 通常使用 XAML 代码编辑器窗口设计用户界面(UI),同时使用 XAML 设计器窗口预览结果。 -
XAML 设计器
这是 XAML 文档的设计器。 它是交互式的,可以从“工具箱”拖放对象。 通过选择和移动设计器中的项,可以直观地为应用组合 UI。
当设计器和编辑器都可见时,对设计器的更改会反映在编辑器中,反之亦然。
在设计器中选择项时,“ 属性” 窗口将显示有关该对象的属性和属性。 -
XAML 代码编辑器
这是 XAML 文档的 XAML 代码编辑器。 XAML 代码编辑器是一种无需设计器即可手动创建 UI 的方法。 在设计器中添加控件时,设计器可能会自动设置控件的属性。 XAML 代码编辑器则为你提供更多控制权。
当设计器和编辑器都可见时,对设计器的更改会反映在编辑器中,反之亦然。 在代码编辑器中导航文本插入符号时,“ 属性” 窗口将显示有关该对象的属性和属性。
四、检查 XAML
创建项目后,将显示 XAML 代码编辑器,并以最少的 XAML 代码显示窗口。 如果未打开编辑器,请在解决方案资源管理器窗口中双击 MainWindow.xaml 项。 你应该会看到类似于以下示例的 XAML:
<Window x:Class="Names.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Names"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
如果要在 Visual Basic 中编码,则 XAML 略有不同,特别是 x:Class=“…” 属性。 Visual Basic 中的 XAML 使用对象的类名,并将命名空间省略到该类。
为了更好地了解 XAML,让我们将其分解。 XAML 只是由 WPF 处理以创建 UI 的 XML。 若要了解 XAML,至少应熟悉 XML 的基础知识。
文档根 表示 XAML 文件描述的对象类型。 它声明八个特性,这些特性通常分为三类:
-
XML 命名空间
XML 命名空间为 XML 提供结构,确定可在文件中声明的 XML 内容。
主要 xmlns 特性将导入整个文件的 XML 命名空间,在本例中,将映射到 WPF 声明的类型。 其他 XML 命名空间声明一个前缀,并导入 XAML 文件的其他类型和对象。 例如,xmlns:local 命名空间声明 local 前缀,并映射到项目声明的对象,即,在 Names 代码命名空间中声明的对象。 -
x:Class 属性
此属性将映射到 代码定义的类型: MainWindow.xaml.cs 或 MainWindow.xaml.vb 文件,该文件是 Names.MainWindow C# 和 MainWindow Visual Basic 中的类。 -
Title 属性
在 XAML 对象上声明的任何常规特性都会设置该对象的属性。 在本例中,Title 特性将设置 Window.Title 属性。
五、更改窗口
对于我们的示例应用,此窗口太大,并且标题栏不是描述性的。 现在来解决此问题。
- 首先,按 F5 键或从菜单中选择“调试>开始调试”来运行应用。
你将看到模板生成的默认窗口,其中未显示任何控件,以及 MainWindow 的标题:
-
通过将窗口的标题设置为 Title Names。
-
通过设置 Width 到 180 和 Height 更改为 260更改窗口的大小。
<Window x:Class="Names.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Names"
mc:Ignorable="d"
Title="Names" Height="180" Width="260">
<Grid>
</Grid>
</Window>
六、准备布局
WPF 提供一个功能强大的布局系统,其中包含许多不同的布局控件。 布局控件可帮助放置子控件和调整其大小,甚至可以自动执行这些操作。 此 XAML 中提供给你的默认布局控件是 控件。
网格控件允许你定义行和列,这与表非常类似,并将控件放置在特定行和列组合的边界内。 可以将任意数量的子控件或其他布局控件添加到网格中。 例如,可以将另一个 控件置于特定的行和列组合中,然后新网格可以定义更多行和列,并具有自己的子级。
网格控件将其子控件放在行和列中。 网格始终只声明单行和单列,这意味着默认情况下,网格就是一个单元格。 这并不能让你真正灵活地放置控件。
调整此应用所需的控件的网格布局。
-
向 元素添加新属性: Margin=“10”。
此设置将网格从窗口边缘引入,使其看起来更美观。 -
定义两行和两列,将网格划分为四个单元格:
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
- 在 XAML 代码编辑器或 XAML 设计器中选择网格,你将看到 XAML 设计器显示每一行和每一列:
七、添加第一个控件
配置网格后,我们可以开始向其添加控件。 首先,从标签控件开始。
- 在元素内在行和列定义之后创建一个新
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label>Names</Label>
</Grid>
定义内容 Names。 有些控件知道如何处理内容,有些则不知道。 控件的内容映射到 Content 属性。 通过 XAML 特性语法设置内容时,将使用以下格式:
请注意,标签占据窗口的一半,因为它自动定位到网格的第一行和列。 对于第一行,我们不需要那么多空间,因为我们只需要在这一行放置标签。
- 将第一个 的 Height 特性从 * 更改为 Auto。
Auto 值会自动将网格行的大小调整为其内容(在本例中为标签控件)的大小。
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
请注意,设计器现在显示标签占据的可用高度较少。 现在,下一行有更多空间可用。
八、控件放置
让我们谈谈控件的放置。 在上一节中创建的标签自动放置在网格的第 0 行和第 0 列。 行和列的编号从 0 开始,递增 1。 控件无法识别网格,并且不会定义任何属性来控制其在网格中的位置。
当控件无法识别网格时,如何告诉控件使用其他行或列? 附加属性! 网格采用 WPF 提供的强大属性系统。
网格控件定义子控件可以附加到自己的新属性。 控件本身上实际上不存在这些属性,一旦控件添加到网格中,这些属性就可供控件使用。
网格定义两个属性来确定子控件的行和列位置:Grid.Row 和 Grid.Column。 如果控件中省略了这些属性,则意味着它们的默认值为 0,因此,控件将放置在网格的第 0 行和第 0 列。 尝试通过将 Grid.Column 属性设置为 1 来更改
<Label Grid.Column="1">Names</Label>
请注意,标签移动到第二列。 你可以使用 Grid.Row 和 Grid.Column 附加属性来放置我们接下来要创建的控件。 不过现在,请将标签还原到第 0 列。
九、创建名称列表框
现在已经正确调整了网格的大小并创建了标签,接下来,在标签下方的行中添加一个列表框控件。
-
声明控件下的
-
将 Grid.Row 属性设置为 1。
-
将 x:Name 属性设置为 lstNames。
为控件命名后,即可在代码隐藏中对其进行引用。 该名称通过 x:Name 特性分配给控件。
XAML 应如下所示:
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label>Names</Label>
<ListBox Grid.Row="1" x:Name="lstNames" />
</Grid>
十、添加其余控件
我们将添加的最后两个控件是一个文本框和一个按钮,用户使用该文本框输入名称以添加到列表框。 但是,我们不会尝试在网格中创建更多行和列来排列这些控件,而是将这些控件放入 布局控件中。
堆叠面板与网格的不同之处在于控件的放置方式。 当告知网格希望控件与Grid.RowGrid.Column附加属性位于何处时,堆栈面板会自动按顺序排列其每个子控件。 它互相“堆叠”每个控件。
-
声明控件下的控件。
-
将 Grid.Row 属性设置为 1。
-
将 Grid.Column 属性设置为 1。
-
将 Margin 设置为 5,0,0,0。
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label>Names</Label>
<ListBox Grid.Row="1" x:Name="lstNames" />
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5,0,0,0">
</StackPanel>
之前在网格上使用了 Margin 特性,但我们只输入了一个值 (10)。 此边距的值 5,0,0,0与值大相径 10庭。 margin 属性是一种类型,可以解释这两个 Thickness 值。 粗细定义矩形框每条边(分别为左、顶、右、底)周围的空间。 如果边距的值是单一值,则四条边均使用该值。
- 在 控件内部,创建一个 控件。
将 x:Name 属性设置为 txtName。 - 最后,在之后 ,仍在内部 创建控件 。
将 x:Name 属性设置为 btnAdd。
将 Margin 设置为 0,5,0,0。
将内容设置为 Add Name.
XAML 应如下所示:
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5,0,0,0">
<TextBox x:Name="txtName" />
<Button x:Name="btnAdd" Margin="0,5,0,0">Add Name</Button>
</StackPanel>
窗口的布局已完成。 但是,我们的应用不包含任何逻辑,无法真正发挥作用。 接下来,我们需要将控件事件挂钩到代码,让应用能够实际派上用场。
十一、为 Click 事件添加代码
我们创建的 具有一个 Click 事件,该事件在用户按下按钮时引发。 你可以订阅此事件并添加代码,以便向列表框添加名称。 XAML 属性用于订阅事件,就像用于设置属性一样。
-
找到控件 。
-
将 Click 特性设置为 ButtonAddName_Click
<StackPanel Grid.Row="1" Grid.Column="1" Margin="5,0,0,0">
<TextBox x:Name="txtName" />
<Button x:Name="btnAdd" Margin="0,5,0,0" Click="ButtonAddName_Click">Add Name</Button>
</StackPanel>
- 生成事件处理程序代码。 右键单击 ButtonAddName_Click,然后选择“转到定义”。
此操作在代码隐藏中生成与提供的处理程序名称匹配的方法。
private void ButtonAddName_Click(object sender, RoutedEventArgs e)
{
}
- 接下来,添加以下代码以执行这三个步骤:
确保文本框包含名称。
验证文本框中输入的名称是否已经存在。
将名称添加到列表框。
private void ButtonAddName_Click(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(txtName.Text) && !lstNames.Items.Contains(txtName.Text))
{
lstNames.Items.Add(txtName.Text);
txtName.Clear();
}
}
十二、运行应用
处理事件后,请运行应用。 随即显示窗口,可以在文本框中输入名称,然后通过单击按钮添加该名称。