本文介绍如何开发 Windows Presentation Foundation(WPF)桌面应用程序,其中包含大多数 WPF 应用程序通用的元素:可扩展应用程序标记语言(XAML)标记、代码隐藏、应用程序定义、控件、布局、数据绑定和样式。 若要开发应用程序,你将使用 Visual Studio。
重要
本文是针对 .NET Framework 编写的。 若要开始使用 .NET,请参阅教程:创建新的 WPF 应用(WPF .NET)。
本教程中,您将学习如何:
- 创建 WPF 项目。
- 使用 XAML 设计应用程序用户界面(UI)的外观。
- 编写代码以生成应用程序的行为。
- 创建用于管理应用程序的应用程序定义。
- 添加控件并创建布局以撰写应用程序 UI。
- 创建样式以在整个应用程序的 UI 中保持一致的外观。
- 将 UI 绑定到数据,既要填充数据中的 UI,又要使数据和 UI 保持同步。
本教程结束时,你将构建一个独立的 Windows 应用程序,允许用户查看所选人员的支出报表。 该应用程序由多个 WPF 页面组成,这些页面托管在浏览器样式窗口中。
小窍门
本教程中使用的示例代码适用于 教程 WPF 应用示例代码中的 Visual Basic 和 C# 。
可以使用本页顶部的语言选择器在 C# 和 Visual Basic 之间切换示例代码的代码语言。
先决条件
安装了Visual Studio 2019并启用了.NET 桌面开发工作负载。
有关安装最新版本的 Visual Studio 的详细信息,请参阅 “安装 Visual Studio”。
创建应用程序项目
第一步是创建应用程序基础结构,其中包括应用程序定义、两页和一个图像。
在 Visual Basic 或 Visual C# 中创建名为
ExpenseIt
:打开 Visual Studio,然后选择“开始”菜单下的“创建新项目”。
此时会打开 “创建新项目 ”对话框。
在 “语言 ”下拉列表中,选择 C# 或 Visual Basic。
选择 WPF 应用(.NET Framework) 模板,然后选择“ 下一步”。
此时会打开 “配置新项目 ”对话框。
输入项目名称
ExpenseIt
,然后选择“ 创建”。Visual Studio 创建项目,并打开名为 MainWindow.xaml 的默认应用程序窗口的设计器。
打开 Application.xaml (Visual Basic)或 App.xaml (C#)。
此 XAML 文件定义 WPF 应用程序和任何应用程序资源。 还可以使用此文件来指定 UI,在本例中, MainWindow.xaml 会在应用程序启动时自动显示。
XAML 在 Visual Basic 中应如下所示:
<Application x:Class="Application" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml"> <Application.Resources> </Application.Resources> </Application>
在 C# 中如下所示:
<Application x:Class="ExpenseIt.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml"> <Application.Resources> </Application.Resources> </Application>
打开 MainWindow.xaml。
此 XAML 文件是应用程序的主窗口,并显示在页面中创建的内容。 该 Window 类定义窗口的属性,例如窗口的标题、大小或图标,并处理事件,例如关闭或隐藏。
将 Window 元素更改为 a NavigationWindow,如以下 XAML 所示:
<NavigationWindow x:Class="ExpenseIt.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" ... </NavigationWindow>
此应用根据用户输入导航到不同的内容。 这就是为什么主要 Window 需要更改为 a NavigationWindow。 NavigationWindow 继承 . 的所有属性 Window。 XAML 文件中的NavigationWindow元素创建了NavigationWindow类的实例。 有关详细信息,请参阅 导航概述。
从NavigationWindow标签之间删除Grid元素。
更改元素的 XAML 代码 NavigationWindow 中的以下属性:
你的 XAML 应如下所示,适用于 Visual Basic:
<NavigationWindow x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ExpenseIt" Height="350" Width="500"> </NavigationWindow>
对于 C#,如下所示:
<NavigationWindow x:Class="ExpenseIt.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ExpenseIt" Height="350" Width="500"> </NavigationWindow>
打开 MainWindow.xaml.vb 或 MainWindow.xaml.cs。
此文件是一个代码隐藏文件,其中包含用于处理 MainWindow.xaml 中声明的事件的代码。 此文件包含 XAML 中定义的窗口的分部类。
如果使用的是 C#,请将
MainWindow
类更改为派生自 NavigationWindow。 (在 Visual Basic 中,在 XAML 中更改窗口时会自动发生这种情况。C# 代码现在应如下所示:using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ExpenseIt { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : NavigationWindow { public MainWindow() { InitializeComponent(); } } }
将文件添加到应用程序
在本部分中,你将向应用程序添加两个页面和一个图像。
向项目添加新页面,并将其命名
ExpenseItHome.xaml
为:在 解决方案资源管理器中,右键单击
ExpenseIt
项目节点,然后选择“ 添加>页面”。在“ 添加新项 ”对话框中,已选择 “页面”(WPF) 模板。 输入名称
ExpenseItHome
,然后选择“ 添加”。
此页面是启动应用程序时显示的第一页。 它将显示要从中选择的人员列表,以显示费用报表。
打开
ExpenseItHome.xaml
。将 Title 设置为 “
ExpenseIt - Home
”。将
DesignHeight
设置为 350 像素和DesignWidth
500 像素。现在,VISUAL Basic 的 XAML 如下所示:
<Page x:Class="ExpenseItHome" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="350" d:DesignWidth="500" Title="ExpenseIt - Home"> <Grid> </Grid> </Page>
对于 C#,如下所示:
<Page x:Class="ExpenseIt.ExpenseItHome" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="350" d:DesignWidth="500" Title="ExpenseIt - Home"> <Grid> </Grid> </Page>
打开 MainWindow.xaml。
添加一个Source属性到NavigationWindow元素,并将其设置为“
ExpenseItHome.xaml
”。这设置为
ExpenseItHome.xaml
应用程序启动时打开的第一页。Visual Basic 中的示例 XAML:
<NavigationWindow x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ExpenseIt" Height="350" Width="500" Source="ExpenseItHome.xaml"> </NavigationWindow>
在 C# 中:
<NavigationWindow x:Class="ExpenseIt.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ExpenseIt" Height="350" Width="500" Source="ExpenseItHome.xaml"> </NavigationWindow>
小窍门
还可以在“属性”窗口的“杂项”类别中设置“源”属性。
将另一个新的 WPF 页添加到项目,并将其命名为 ExpenseReportPage.xaml::
在 解决方案资源管理器中,右键单击
ExpenseIt
项目节点,然后选择“ 添加>页面”。在“ 添加新项 ”对话框中,选择 “页面”(WPF) 模板。 输入名称 ExpenseReportPage,然后选择“ 添加”。
此页面将显示页面上所选
ExpenseItHome
人员的支出报表。打开 ExpenseReportPage.xaml。
将 Title 设置为 "
ExpenseIt - View Expense
"。将
DesignHeight
设置为 350 像素和DesignWidth
500 像素。ExpenseReportPage.xaml 现在在 Visual Basic 中如下所示:
<Page x:Class="ExpenseReportPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="350" d:DesignWidth="500" Title="ExpenseIt - View Expense"> <Grid> </Grid> </Page>
在 C# 中如下所示:
<Page x:Class="ExpenseIt.ExpenseReportPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="350" d:DesignWidth="500" Title="ExpenseIt - View Expense"> <Grid> </Grid> </Page>
打开 ExpenseItHome.xaml.vb 和 ExpenseReportPage.xaml.vb,或 ExpenseItHome.xaml.cs 和 ExpenseReportPage.xaml.cs。
创建新的页面文件时,Visual Studio 会自动创建其 代码隐藏 文件。 这些代码隐藏文件负责处理响应用户输入的逻辑。
您编写的代码应对于
ExpenseItHome
如下所示:using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ExpenseIt { /// <summary> /// Interaction logic for ExpenseItHome.xaml /// </summary> public partial class ExpenseItHome : Page { public ExpenseItHome() { InitializeComponent(); } } }
Class ExpenseItHome End Class
与 ExpenseReportPage 的以下内容类似:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ExpenseIt { /// <summary> /// Interaction logic for ExpenseReportPage.xaml /// </summary> public partial class ExpenseReportPage : Page { public ExpenseReportPage() { InitializeComponent(); } } }
Class ExpenseReportPage End Class
向项目添加名为 watermark.png 的图像。 可以创建自己的映像、从示例代码复制文件,或者从 microsoft/WPF-Samples GitHub 存储库获取该文件。
右键单击项目节点并选择“ 添加>现有项”,或按 Shift+Alt+A。
在 “添加现有项 ”对话框中,将文件筛选器设置为 “所有文件 ”或“ 图像文件”,浏览到要使用的图像文件,然后选择“ 添加”。
在 解决方案资源管理器中选择映像文件,然后在 “属性” 窗口中,将 “生成作 ”设置为 “资源”。
生成并运行应用程序
若要生成并运行应用程序,请按 F5 或从“调试”菜单中选择“开始调试”。
下图显示了带有 NavigationWindow 按钮的应用程序:
关闭应用程序以返回到 Visual Studio。
创建布局
布局提供了放置 UI 元素的有序方法,并在调整 UI 大小时管理这些元素的大小和位置。 通常使用以下布局控件之一创建布局:
- Canvas - 定义一个区域,您可以使用相对于 Canvas 区域的坐标来显式定位该区域内的子元素。
- DockPanel - 定义一个区域,可在其中水平或垂直排列子元素,彼此相对。
- Grid - 定义由列和行组成的灵活网格区域。
- StackPanel - 将子元素排列成可水平或垂直方向的单个线条。
- VirtualizingStackPanel - 在水平或垂直方向的单个行上排列和虚拟化内容。
- WrapPanel - 将子元素放在从左到右的顺序位置,将内容中断到包含框边缘的下一行。 后续排序按顺序从上到下或从右到左的顺序进行,具体取决于 Orientation 属性的值。
其中每个布局控件都为其子元素支持特定类型的布局。
ExpenseIt
可以调整页面大小,并且每个页面都具有与其他元素一起水平和垂直排列的元素。 在此示例中,Grid 被用作应用程序的布局元素。
在本部分中,通过将列和行定义添加到 Grid in ExpenseItHome.xaml
,创建包含三行和 10 像素边距的单列表。
在
ExpenseItHome.xaml
中,将MarginGrid元素上的属性设置为“10,0,10,10”,对应于左、上、右和下边距:<Grid Margin="10,0,10,10">
小窍门
还可以在“属性”窗口中在“布局”类别下设置边距值:
在 Grid 标记之间添加以下 XAML 来定义行和列:
<Grid.ColumnDefinitions> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition /> <RowDefinition Height="Auto"/> </Grid.RowDefinitions>
将Height的两行设置为Auto,这意味着根据其内容调整行的大小。 默认值 Height 为 Star 大小调整,这意味着行高是可用空间的加权比例。 例如,如果两行各有一个 Height “*”,则每个行的高度为可用空间的一半。
您的 Grid 现在应包含以下 XAML:
<Grid Margin="10,0,10,10"> <Grid.ColumnDefinitions> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition /> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> </Grid>
添加控件
在本部分中,你将更新主页的 UI 以显示人物列表,并在其中选择一个人来显示该人的费用报表。 控件是允许用户与应用程序交互的 UI 对象。 有关详细信息,请参阅 控件。
若要创建此 UI,需要将以下元素添加到 ExpenseItHome.xaml
:
在Grid的某一行中通过设置Grid.Row附加属性放置每个控件。 有关附加属性的详细信息,请参阅 “附加属性概述”。
在 Grid 标签之间的某处
ExpenseItHome.xaml
,添加以下 XAML:<!-- People list --> <Border Grid.Column="0" Grid.Row="0" Height="35" Padding="5" Background="#4E87D4"> <Label VerticalAlignment="Center" Foreground="White">Names</Label> </Border> <ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1"> <ListBoxItem>Mike</ListBoxItem> <ListBoxItem>Lisa</ListBoxItem> <ListBoxItem>John</ListBoxItem> <ListBoxItem>Mary</ListBoxItem> </ListBox> <!-- View report button --> <Button Grid.Column="0" Grid.Row="2" Margin="0,10,0,10" Width="125" Height="25" HorizontalAlignment="Right">View</Button>
小窍门
还可以通过将控件从 工具箱 窗口拖动到设计窗口,然后在 “属性” 窗口中设置控件的属性来创建控件。
生成并运行应用程序。
下图显示了创建的控件:
添加图像和标题
在本部分中,你将使用图像和页面标题更新主页 UI。
在
ExpenseItHome.xaml
中,将固定宽度为 230 像素的另一列添加到 ColumnDefinitions 中。<Grid.ColumnDefinitions> <ColumnDefinition Width="230" /> <ColumnDefinition /> </Grid.ColumnDefinitions>
将另一行添加到 RowDefinitions,共四行:
<Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="Auto"/> <RowDefinition /> <RowDefinition Height="Auto"/> </Grid.RowDefinitions>
通过在三个控件(Border、ListBox 和 Button)中的每一个控件中将 `Grid.Column` 属性设置为 1,把控件移动到第二列。
将每个控件(边框、ListBox 和 Button)及 Border 元素的 Grid.Row 值递增 1,从而使每个控件下移一行。
三个控件的 XAML 现在如下所示:
<Border Grid.Column="1" Grid.Row="1" Height="35" Padding="5" Background="#4E87D4"> <Label VerticalAlignment="Center" Foreground="White">Names</Label> </Border> <ListBox Name="peopleListBox" Grid.Column="1" Grid.Row="2"> <ListBoxItem>Mike</ListBoxItem> <ListBoxItem>Lisa</ListBoxItem> <ListBoxItem>John</ListBoxItem> <ListBoxItem>Mary</ListBoxItem> </ListBox> <!-- View report button --> <Button Grid.Column="1" Grid.Row="3" Margin="0,10,0,0" Width="125" Height="25" HorizontalAlignment="Right">View</Button>
将以下 XAML 添加到
<Grid>
和</Grid>
标签之间的任意位置,以将 Background 属性设置为 watermark.png 图像文件:<Grid.Background> <ImageBrush ImageSource="watermark.png"/> </Grid.Background>
在 Border 元素之前,添加 Label 内容为“查看费用报表”。 此标签是页面的标题。
<Label Grid.Column="1" VerticalAlignment="Center" FontFamily="Trebuchet MS" FontWeight="Bold" FontSize="18" Foreground="#0066cc"> View Expense Report </Label>
生成并运行应用程序。
下图显示了刚刚添加的内容的结果:
添加代码以处理事件
在
ExpenseItHome.xaml
中,向 Click 元素添加事件处理程序 Button 。 有关详细信息,请参阅 如何:创建简单的事件处理程序。<!-- View report button --> <Button Grid.Column="1" Grid.Row="3" Margin="0,10,0,0" Width="125" Height="25" HorizontalAlignment="Right" Click="Button_Click">View</Button>
打开
ExpenseItHome.xaml.vb
或ExpenseItHome.xaml.cs
。将以下代码添加到
ExpenseItHome
类,以添加按钮单击事件处理程序。 事件处理程序将打开 ExpenseReportPage 页。private void Button_Click(object sender, RoutedEventArgs e) { // View Expense Report ExpenseReportPage expenseReportPage = new ExpenseReportPage(); this.NavigationService.Navigate(expenseReportPage); }
Private Sub Button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) ' View Expense Report Dim expenseReportPage As New ExpenseReportPage() Me.NavigationService.Navigate(expenseReportPage) End Sub
创建 ExpenseReportPage 的 UI
ExpenseReportPage.xaml 显示页面上所选 ExpenseItHome
人员的支出报表。 在本部分中,你将为 ExpenseReportPage 创建 UI。 你还将向各种 UI 元素添加背景和填充颜色。
打开 ExpenseReportPage.xaml。
在Grid标签之间添加以下XAML:
<Grid.Background> <ImageBrush ImageSource="watermark.png" /> </Grid.Background> <Grid.ColumnDefinitions> <ColumnDefinition Width="230" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <Label Grid.Column="1" VerticalAlignment="Center" FontFamily="Trebuchet MS" FontWeight="Bold" FontSize="18" Foreground="#0066cc"> Expense Report For: </Label> <Grid Margin="10" Grid.Column="1" Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <!-- Name --> <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Orientation="Horizontal"> <Label Margin="0,0,0,5" FontWeight="Bold">Name:</Label> <Label Margin="0,0,0,5" FontWeight="Bold"></Label> </StackPanel> <!-- Department --> <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Orientation="Horizontal"> <Label Margin="0,0,0,5" FontWeight="Bold">Department:</Label> <Label Margin="0,0,0,5" FontWeight="Bold"></Label> </StackPanel> <Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" VerticalAlignment="Top" HorizontalAlignment="Left"> <!-- Expense type and Amount table --> <DataGrid AutoGenerateColumns="False" RowHeaderWidth="0" > <DataGrid.ColumnHeaderStyle> <Style TargetType="{x:Type DataGridColumnHeader}"> <Setter Property="Height" Value="35" /> <Setter Property="Padding" Value="5" /> <Setter Property="Background" Value="#4E87D4" /> <Setter Property="Foreground" Value="White" /> </Style> </DataGrid.ColumnHeaderStyle> <DataGrid.Columns> <DataGridTextColumn Header="ExpenseType" /> <DataGridTextColumn Header="Amount" /> </DataGrid.Columns> </DataGrid> </Grid> </Grid>
此界面类似于
ExpenseItHome.xaml
,但报表数据显示在一个 DataGrid中。生成并运行应用程序。
选择 “视图 ”按钮。
费用报告页面出现了。 另请注意,已启用后退导航按钮。
下图显示了添加到 ExpenseReportPage.xaml 的 UI 元素。
样式控件
对于 UI 中具有相同类型的所有元素,各种元素的外观通常相同。 UI 使用 样式 使外观可跨多个元素重复使用。 样式的可重用性有助于简化 XAML 的创建和管理。 本部分将前面步骤中定义的每元素属性替换为样式。
打开 Application.xaml 或 App.xaml。
在 Application.Resources 标签之间添加以下 XAML:
<!-- Header text style --> <Style x:Key="headerTextStyle"> <Setter Property="Label.VerticalAlignment" Value="Center"></Setter> <Setter Property="Label.FontFamily" Value="Trebuchet MS"></Setter> <Setter Property="Label.FontWeight" Value="Bold"></Setter> <Setter Property="Label.FontSize" Value="18"></Setter> <Setter Property="Label.Foreground" Value="#0066cc"></Setter> </Style> <!-- Label style --> <Style x:Key="labelStyle" TargetType="{x:Type Label}"> <Setter Property="VerticalAlignment" Value="Top" /> <Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="Margin" Value="0,0,0,5" /> </Style> <!-- DataGrid header style --> <Style x:Key="columnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}"> <Setter Property="Height" Value="35" /> <Setter Property="Padding" Value="5" /> <Setter Property="Background" Value="#4E87D4" /> <Setter Property="Foreground" Value="White" /> </Style> <!-- List header style --> <Style x:Key="listHeaderStyle" TargetType="{x:Type Border}"> <Setter Property="Height" Value="35" /> <Setter Property="Padding" Value="5" /> <Setter Property="Background" Value="#4E87D4" /> </Style> <!-- List header text style --> <Style x:Key="listHeaderTextStyle" TargetType="{x:Type Label}"> <Setter Property="Foreground" Value="White" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="HorizontalAlignment" Value="Left" /> </Style> <!-- Button style --> <Style x:Key="buttonStyle" TargetType="{x:Type Button}"> <Setter Property="Width" Value="125" /> <Setter Property="Height" Value="25" /> <Setter Property="Margin" Value="0,10,0,0" /> <Setter Property="HorizontalAlignment" Value="Right" /> </Style>
此 XAML 添加以下样式:
headerTextStyle
:设置页面标题 Label的格式。labelStyle
:为Label控件设置格式。columnHeaderStyle
:将DataGridColumnHeader格式化。listHeaderStyle
:设置列表标头 Border 控件的格式。listHeaderTextStyle
:设置列表标头 Label的格式。buttonStyle
:在ExpenseItHome.xaml
上格式化Button。
请注意,样式是属性元素的资源和子 Application.Resources 元素。 在此位置,样式将应用于应用程序中的所有元素。 有关在 .NET 应用中使用资源的示例,请参阅 “使用应用程序资源”。
在
ExpenseItHome.xaml
中,将 Grid 元素之间的所有内容替换为以下 XAML:<Grid.Background> <ImageBrush ImageSource="watermark.png" /> </Grid.Background> <Grid.ColumnDefinitions> <ColumnDefinition Width="230" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="Auto"/> <RowDefinition /> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <!-- People list --> <Label Grid.Column="1" Style="{StaticResource headerTextStyle}" > View Expense Report </Label> <Border Grid.Column="1" Grid.Row="1" Style="{StaticResource listHeaderStyle}"> <Label Style="{StaticResource listHeaderTextStyle}">Names</Label> </Border> <ListBox Name="peopleListBox" Grid.Column="1" Grid.Row="2"> <ListBoxItem>Mike</ListBoxItem> <ListBoxItem>Lisa</ListBoxItem> <ListBoxItem>John</ListBoxItem> <ListBoxItem>Mary</ListBoxItem> </ListBox> <!-- View report button --> <Button Grid.Column="1" Grid.Row="3" Click="Button_Click" Style="{StaticResource buttonStyle}">View</Button>
定义每个控件外观的属性,如VerticalAlignment和FontFamily,已被删除,并通过应用样式进行替换。 例如,
headerTextStyle
是应用于“查看费用报表”Label。打开 ExpenseReportPage.xaml。
将 Grid 元素之间的所有内容替换为以下 XAML:
<Grid.Background> <ImageBrush ImageSource="watermark.png" /> </Grid.Background> <Grid.ColumnDefinitions> <ColumnDefinition Width="230" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <Label Grid.Column="1" Style="{StaticResource headerTextStyle}"> Expense Report For: </Label> <Grid Margin="10" Grid.Column="1" Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <!-- Name --> <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Orientation="Horizontal"> <Label Style="{StaticResource labelStyle}">Name:</Label> <Label Style="{StaticResource labelStyle}"></Label> </StackPanel> <!-- Department --> <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Orientation="Horizontal"> <Label Style="{StaticResource labelStyle}">Department:</Label> <Label Style="{StaticResource labelStyle}"></Label> </StackPanel> <Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" VerticalAlignment="Top" HorizontalAlignment="Left"> <!-- Expense type and Amount table --> <DataGrid ColumnHeaderStyle="{StaticResource columnHeaderStyle}" AutoGenerateColumns="False" RowHeaderWidth="0" > <DataGrid.Columns> <DataGridTextColumn Header="ExpenseType" /> <DataGridTextColumn Header="Amount" /> </DataGrid.Columns> </DataGrid> </Grid> </Grid>
生成并运行应用程序。 窗口外观与之前的外观相同。
关闭应用程序以返回到 Visual Studio。
将数据绑定到控件
在本部分中,你将创建绑定到各种控件的 XML 数据。
在
ExpenseItHome.xaml
开始 Grid 元素之后,添加以下 XAML 以创建一个包含每个人数据的 XmlDataProvider:<Grid.Resources> <!-- Expense Report Data --> <XmlDataProvider x:Key="ExpenseDataSource" XPath="Expenses"> <x:XData> <Expenses xmlns=""> <Person Name="Mike" Department="Legal"> <Expense ExpenseType="Lunch" ExpenseAmount="50" /> <Expense ExpenseType="Transportation" ExpenseAmount="50" /> </Person> <Person Name="Lisa" Department="Marketing"> <Expense ExpenseType="Document printing" ExpenseAmount="50"/> <Expense ExpenseType="Gift" ExpenseAmount="125" /> </Person> <Person Name="John" Department="Engineering"> <Expense ExpenseType="Magazine subscription" ExpenseAmount="50"/> <Expense ExpenseType="New machine" ExpenseAmount="600" /> <Expense ExpenseType="Software" ExpenseAmount="500" /> </Person> <Person Name="Mary" Department="Finance"> <Expense ExpenseType="Dinner" ExpenseAmount="100" /> </Person> </Expenses> </x:XData> </XmlDataProvider> </Grid.Resources>
数据作为 Grid 资源创建。 通常,此数据将作为文件加载,但为简单起见,数据将内联添加。
在
<Grid.Resources>
元素中添加以下<xref:System.Windows.DataTemplate>
元素,该元素定义如何在<XmlDataProvider>
元素之后显示ListBox中的数据。<Grid.Resources> <!-- Name item template --> <DataTemplate x:Key="nameItemTemplate"> <Label Content="{Binding XPath=@Name}"/> </DataTemplate> </Grid.Resources>
有关数据模板的详细信息,请参阅 数据模板概述。
将现有 ListBox 代码替换为以下 XAML:
<ListBox Name="peopleListBox" Grid.Column="1" Grid.Row="2" ItemsSource="{Binding Source={StaticResource ExpenseDataSource}, XPath=Person}" ItemTemplate="{StaticResource nameItemTemplate}"> </ListBox>
此 XAML 将 ListBox 的属性 ItemsSource 绑定到数据源,并将数据模板应用于作为 ItemTemplate。
将数据连接到控件
接下来,将添加代码以检索在 ExpenseItHome
页上选择的名称,并将其传递给 ExpenseReportPage 的构造函数。
ExpenseReportPage 使用传递的项设置其数据上下文,这是 ExpenseReportPage.xaml 中定义的控件绑定到的内容。
打开 ExpenseReportPage.xaml.vb 或 ExpenseReportPage.xaml.cs。
添加采用对象的构造函数,以便传递所选人员的支出报表数据。
public partial class ExpenseReportPage : Page { public ExpenseReportPage() { InitializeComponent(); } // Custom constructor to pass expense report data public ExpenseReportPage(object data):this() { // Bind to expense report data. this.DataContext = data; } }
Partial Public Class ExpenseReportPage Inherits Page Public Sub New() InitializeComponent() End Sub ' Custom constructor to pass expense report data Public Sub New(ByVal data As Object) Me.New() ' Bind to expense report data. Me.DataContext = data End Sub End Class
打开
ExpenseItHome.xaml.vb
或ExpenseItHome.xaml.cs
。更改 Click 事件处理程序以调用传递所选人员的支出报表数据的新构造函数。
private void Button_Click(object sender, RoutedEventArgs e) { // View Expense Report ExpenseReportPage expenseReportPage = new ExpenseReportPage(this.peopleListBox.SelectedItem); this.NavigationService.Navigate(expenseReportPage); }
Private Sub Button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) ' View Expense Report Dim expenseReportPage As New ExpenseReportPage(Me.peopleListBox.SelectedItem) Me.NavigationService.Navigate(expenseReportPage) End Sub
使用数据模板设置数据样式
在本部分中,你将使用数据模板更新数据绑定列表中每个项的 UI。
打开 ExpenseReportPage.xaml。
将“Name”和“Department” Label 元素的内容绑定到相应的数据源属性。 有关数据绑定的详细信息,请参阅 数据绑定概述。
<!-- Name --> <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Orientation="Horizontal"> <Label Style="{StaticResource labelStyle}">Name:</Label> <Label Style="{StaticResource labelStyle}" Content="{Binding XPath=@Name}"></Label> </StackPanel> <!-- Department --> <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Orientation="Horizontal"> <Label Style="{StaticResource labelStyle}">Department:</Label> <Label Style="{StaticResource labelStyle}" Content="{Binding XPath=@Department}"></Label> </StackPanel>
打开 Grid 元素后,添加以下数据模板,该模板定义如何显示费用报表数据:
<!--Templates to display expense report data--> <Grid.Resources> <!-- Reason item template --> <DataTemplate x:Key="typeItemTemplate"> <Label Content="{Binding XPath=@ExpenseType}"/> </DataTemplate> <!-- Amount item template --> <DataTemplate x:Key="amountItemTemplate"> <Label Content="{Binding XPath=@ExpenseAmount}"/> </DataTemplate> </Grid.Resources>
将 DataGridTextColumn 元素替换为 DataGridTemplateColumn 元素下 DataGrid ,并向其应用模板。 此外,请在
DataGrid
元素中指定ItemsSource
属性及其值。<!-- Expense type and Amount table --> <DataGrid ItemsSource="{Binding XPath=Expense}" ColumnHeaderStyle="{StaticResource columnHeaderStyle}" AutoGenerateColumns="False" RowHeaderWidth="0" > <DataGrid.Columns> <DataGridTemplateColumn Header="ExpenseType" CellTemplate="{StaticResource typeItemTemplate}" /> <DataGridTemplateColumn Header="Amount" CellTemplate="{StaticResource amountItemTemplate}" /> </DataGrid.Columns> </DataGrid>
生成并运行应用程序。
选择人员,然后选择 “视图 ”按钮。
下图显示了应用程序的两个页面 ExpenseIt
,其中应用了控件、布局、样式、数据绑定和数据模板:
注释
此示例演示了 WPF 的特定功能,并不遵循安全、本地化和辅助功能等所有最佳做法。 有关 WPF 和 .NET 应用程序开发最佳实践的详细介绍,请参考以下主题:
后续步骤
在本演练中,你学习了许多使用 Windows Presentation Foundation (WPF) 创建 UI 的技术。 现在,你应该对数据绑定的 .NET 应用的构建基块有基本的了解。 有关 WPF 体系结构和编程模型的详细信息,请参阅以下主题:
有关创建应用程序的详细信息,请参阅以下主题: