文章目录
-
- [第一个 WPF 应用程序综合汇总:ExpenseIt 费用报表查看器](#第一个 WPF 应用程序综合汇总:ExpenseIt 费用报表查看器)
- [ExpenseIt 项目完整结构及代码详解](#ExpenseIt 项目完整结构及代码详解)
-
- 一、项目文件结构
- 二、各文件完整代码
-
- [1. App.xaml -- 应用程序资源定义](#1. App.xaml – 应用程序资源定义)
- [2. App.xaml.cs -- 应用程序入口](#2. App.xaml.cs – 应用程序入口)
- [3. MainWindow.xaml -- 导航窗口](#3. MainWindow.xaml – 导航窗口)
- [4. MainWindow.xaml.cs -- 主窗口代码隐藏](#4. MainWindow.xaml.cs – 主窗口代码隐藏)
- [5. ExpenseItHome.xaml -- 主页(人员列表)](#5. ExpenseItHome.xaml – 主页(人员列表))
- [6. ExpenseItHome.xaml.cs -- 主页代码隐藏](#6. ExpenseItHome.xaml.cs – 主页代码隐藏)
- [7. ExpenseReportPage.xaml -- 报表页](#7. ExpenseReportPage.xaml – 报表页)
- [8. ExpenseReportPage.xaml.cs -- 报表页代码隐藏](#8. ExpenseReportPage.xaml.cs – 报表页代码隐藏)
- [9. watermark.png -- 背景图片](#9. watermark.png – 背景图片)
- 三、关键代码详解
-
- [3.1 全局样式定义(App.xaml)](#3.1 全局样式定义(App.xaml))
- [3.2 主窗口(MainWindow.xaml)](#3.2 主窗口(MainWindow.xaml))
- [3.3 主页(ExpenseItHome.xaml)](#3.3 主页(ExpenseItHome.xaml))
-
- [3.3.1 布局与背景](#3.3.1 布局与背景)
- [3.3.2 数据源与数据模板](#3.3.2 数据源与数据模板)
- [3.3.3 界面元素](#3.3.3 界面元素)
- [3.3.4 事件处理(ExpenseItHome.xaml.cs)](#3.3.4 事件处理(ExpenseItHome.xaml.cs))
- [3.4 报表页(ExpenseReportPage.xaml)](#3.4 报表页(ExpenseReportPage.xaml))
-
- [3.4.1 布局与背景](#3.4.1 布局与背景)
- [3.4.2 详细信息区域](#3.4.2 详细信息区域)
- [3.4.3 代码隐藏(ExpenseReportPage.xaml.cs)](#3.4.3 代码隐藏(ExpenseReportPage.xaml.cs))
- [3.5 资源文件(watermark.png)](#3.5 资源文件(watermark.png))
- 四、核心概念与实现机制
- 五、运行效果
- 六、学习要点与扩展建议
第一个 WPF 应用程序综合汇总:ExpenseIt 费用报表查看器
本汇总基于官方教程"在 Visual Studio 2019 中创建第一个 WPF 应用程序",提炼出构建一个完整 WPF 桌面应用(ExpenseIt)的项目结构、关键代码、核心概念与实现步骤。通过这个示例,您可以掌握 WPF 开发的典型流程:从项目创建、界面布局、控件使用、事件处理、样式化、数据绑定到页面导航。
一、程序概述
ExpenseIt 是一个简单的费用报表查看器,包含两个页面:
- 主页(ExpenseItHome):显示人员列表,用户选择一个人员后点击"View"按钮。
- 报表页(ExpenseReportPage):显示所选人员的姓名、部门以及费用明细(类型与金额)。
主窗口使用 NavigationWindow,支持页面导航(前进/后退)。整个应用程序的视觉风格通过全局样式统一,数据来源于内嵌的 XML 数据,并通过数据绑定与数据模板展示。
二、项目结构
ExpenseIt/
├── App.xaml // 应用程序资源定义(全局样式)
├── App.xaml.cs // 应用程序入口(一般不需修改)
├── MainWindow.xaml // 主窗口(导航窗口)
├── MainWindow.xaml.cs // 主窗口代码隐藏
├── ExpenseItHome.xaml // 主页(人员列表)
├── ExpenseItHome.xaml.cs // 主页逻辑(按钮点击)
├── ExpenseReportPage.xaml // 报表页(费用明细)
├── ExpenseReportPage.xaml.cs // 报表页逻辑(接收数据)
├── watermark.png // 背景图片(资源)
└── ExpenseIt.csproj // 项目文件
ExpenseIt 项目完整结构及代码详解
本部分提供教程中构建的 ExpenseIt 项目的完整代码清单,包含所有 XAML 和 C# 文件,以及项目文件结构。您可以直接复制这些代码到 Visual Studio 中创建的项目中,即可运行。
一、项目文件结构
ExpenseIt/
├── Properties/
│ └── AssemblyInfo.cs (自动生成,省略)
├── App.xaml (应用程序定义)
├── App.xaml.cs (应用程序入口代码隐藏)
├── MainWindow.xaml (主窗口,导航窗口)
├── MainWindow.xaml.cs (主窗口代码隐藏)
├── ExpenseItHome.xaml (主页,人员列表)
├── ExpenseItHome.xaml.cs (主页代码隐藏)
├── ExpenseReportPage.xaml (报表页)
├── ExpenseReportPage.xaml.cs (报表页代码隐藏)
├── watermark.png (背景图片,资源)
└── ExpenseIt.csproj (项目文件,自动生成)
二、各文件完整代码
1. App.xaml -- 应用程序资源定义
xml
<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>
<!-- 页面标题样式 -->
<Style x:Key="headerTextStyle">
<Setter Property="Label.VerticalAlignment" Value="Center" />
<Setter Property="Label.FontFamily" Value="Trebuchet MS" />
<Setter Property="Label.FontWeight" Value="Bold" />
<Setter Property="Label.FontSize" Value="18" />
<Setter Property="Label.Foreground" Value="#0066cc" />
</Style>
<!-- 普通标签样式 -->
<Style x:Key="labelStyle" TargetType="Label">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Margin" Value="0,0,0,5" />
</Style>
<!-- DataGrid 列头样式 -->
<Style x:Key="columnHeaderStyle" TargetType="DataGridColumnHeader">
<Setter Property="Height" Value="35" />
<Setter Property="Padding" Value="5" />
<Setter Property="Background" Value="#4E87D4" />
<Setter Property="Foreground" Value="White" />
</Style>
<!-- 列表头边框样式 -->
<Style x:Key="listHeaderStyle" TargetType="Border">
<Setter Property="Height" Value="35" />
<Setter Property="Padding" Value="5" />
<Setter Property="Background" Value="#4E87D4" />
</Style>
<!-- 列表头文字样式 -->
<Style x:Key="listHeaderTextStyle" TargetType="Label">
<Setter Property="Foreground" Value="White" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<!-- 按钮样式 -->
<Style x:Key="buttonStyle" TargetType="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>
</Application.Resources>
</Application>
2. App.xaml.cs -- 应用程序入口
csharp
using System.Windows;
namespace ExpenseIt
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
// 应用程序启动逻辑由 StartupUri 自动处理
// 如有需要,可重写 OnStartup 等方法
}
}
3. MainWindow.xaml -- 导航窗口
xml
<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>
4. MainWindow.xaml.cs -- 主窗口代码隐藏
csharp
using System.Windows.Navigation;
namespace ExpenseIt
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : NavigationWindow
{
public MainWindow()
{
InitializeComponent();
}
}
}
5. ExpenseItHome.xaml -- 主页(人员列表)
xml
<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 Margin="10,0,10,10">
<Grid.Resources>
<!-- 内嵌 XML 数据源 -->
<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>
<!-- 人员列表项的数据模板 -->
<DataTemplate x:Key="nameItemTemplate">
<Label Content="{Binding XPath=@Name}" />
</DataTemplate>
</Grid.Resources>
<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>
<!-- 标题 -->
<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 x:Name="peopleListBox"
Grid.Column="1"
Grid.Row="2"
ItemsSource="{Binding Source={StaticResource ExpenseDataSource}, XPath=Person}"
ItemTemplate="{StaticResource nameItemTemplate}" />
<!-- 查看按钮 -->
<Button Grid.Column="1"
Grid.Row="3"
Click="Button_Click"
Style="{StaticResource buttonStyle}">
View
</Button>
</Grid>
</Page>
6. ExpenseItHome.xaml.cs -- 主页代码隐藏
csharp
using System.Windows;
using System.Windows.Controls;
namespace ExpenseIt
{
/// <summary>
/// Interaction logic for ExpenseItHome.xaml
/// </summary>
public partial class ExpenseItHome : Page
{
public ExpenseItHome()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// 获取选中的 ListBoxItem(实际是 XmlElement 类型)
object selectedPerson = peopleListBox.SelectedItem;
if (selectedPerson != null)
{
// 创建报表页并传递选中的人员数据
ExpenseReportPage expenseReportPage = new ExpenseReportPage(selectedPerson);
this.NavigationService.Navigate(expenseReportPage);
}
else
{
MessageBox.Show("请先选择一个人。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
}
}
7. ExpenseReportPage.xaml -- 报表页
xml
<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.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.Resources>
<!-- 费用类型列模板 -->
<DataTemplate x:Key="typeItemTemplate">
<Label Content="{Binding XPath=@ExpenseType}" />
</DataTemplate>
<!-- 金额列模板 -->
<DataTemplate x:Key="amountItemTemplate">
<Label Content="{Binding XPath=@ExpenseAmount}" />
</DataTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- 姓名 -->
<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}" />
</StackPanel>
<!-- 部门 -->
<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}" />
</StackPanel>
<!-- 费用明细表 -->
<DataGrid Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="2"
ItemsSource="{Binding XPath=Expense}"
ColumnHeaderStyle="{StaticResource columnHeaderStyle}"
AutoGenerateColumns="False"
RowHeaderWidth="0"
VerticalAlignment="Top"
HorizontalAlignment="Left">
<DataGrid.Columns>
<DataGridTemplateColumn Header="ExpenseType"
CellTemplate="{StaticResource typeItemTemplate}" />
<DataGridTemplateColumn Header="Amount"
CellTemplate="{StaticResource amountItemTemplate}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Grid>
</Page>
8. ExpenseReportPage.xaml.cs -- 报表页代码隐藏
csharp
using System.Windows.Controls;
namespace ExpenseIt
{
/// <summary>
/// Interaction logic for ExpenseReportPage.xaml
/// </summary>
public partial class ExpenseReportPage : Page
{
public ExpenseReportPage()
{
InitializeComponent();
}
/// <summary>
/// 自定义构造函数,接收选中的人员数据对象(XmlNode),并设置为 DataContext
/// </summary>
/// <param name="data">选中的人员 XML 节点</param>
public ExpenseReportPage(object data) : this()
{
this.DataContext = data;
}
}
}
9. watermark.png -- 背景图片
此文件为项目资源,需将其复制到项目根目录,并在"解决方案资源管理器"中设置其"生成操作"为"资源"。
如果您手动创建文件,请确保 .csproj 中包含对图片资源的引用。例如:
xml
xml
<ItemGroup>
<Resource Include="watermark.png" />
</ItemGroup>
三、关键代码详解
3.1 全局样式定义(App.xaml)
在 Application.Resources 中定义多个样式,供整个应用程序复用:
xml
<Application.Resources>
<!-- 页面标题样式 -->
<Style x:Key="headerTextStyle">
<Setter Property="Label.VerticalAlignment" Value="Center"/>
<Setter Property="Label.FontFamily" Value="Trebuchet MS"/>
<Setter Property="Label.FontWeight" Value="Bold"/>
<Setter Property="Label.FontSize" Value="18"/>
<Setter Property="Label.Foreground" Value="#0066cc"/>
</Style>
<!-- 普通标签样式 -->
<Style x:Key="labelStyle" TargetType="Label">
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0,0,0,5"/>
</Style>
<!-- 列表头边框样式 -->
<Style x:Key="listHeaderStyle" TargetType="Border">
<Setter Property="Height" Value="35"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Background" Value="#4E87D4"/>
</Style>
<!-- 列表头文字样式 -->
<Style x:Key="listHeaderTextStyle" TargetType="Label">
<Setter Property="Foreground" Value="White"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
<!-- 按钮样式 -->
<Style x:Key="buttonStyle" TargetType="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>
<!-- DataGrid 列头样式 -->
<Style x:Key="columnHeaderStyle" TargetType="DataGridColumnHeader">
<Setter Property="Height" Value="35"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Background" Value="#4E87D4"/>
<Setter Property="Foreground" Value="White"/>
</Style>
</Application.Resources>
3.2 主窗口(MainWindow.xaml)
将默认的 Window 改为 NavigationWindow,并设置起始页为 ExpenseItHome.xaml:
xml
<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>
代码隐藏只需继承 NavigationWindow 并调用 InitializeComponent()。
3.3 主页(ExpenseItHome.xaml)
3.3.1 布局与背景
使用 Grid 定义两列三行的结构,并设置背景图片:
xml
<Grid Margin="10,0,10,10">
<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>
3.3.2 数据源与数据模板
在 Grid.Resources 中定义内嵌 XML 数据源和人员列表项模板:
xml
<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>
<!-- 其他人员省略 -->
</Expenses>
</x:XData>
</XmlDataProvider>
<DataTemplate x:Key="nameItemTemplate">
<Label Content="{Binding XPath=@Name}"/>
</DataTemplate>
3.3.3 界面元素
放置标题、列表头、ListBox 和按钮,并使用样式和绑定:
xml
<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 x:Name="peopleListBox"
Grid.Column="1" Grid.Row="2"
ItemsSource="{Binding Source={StaticResource ExpenseDataSource}, XPath=Person}"
ItemTemplate="{StaticResource nameItemTemplate}"/>
<Button Grid.Column="1" Grid.Row="3"
Click="Button_Click"
Style="{StaticResource buttonStyle}">View</Button>
3.3.4 事件处理(ExpenseItHome.xaml.cs)
按钮点击时获取选中的 ListBoxItem(实际是 XmlElement 对象),创建报表页并传递数据,然后导航:
csharp
private void Button_Click(object sender, RoutedEventArgs e)
{
object selectedPerson = peopleListBox.SelectedItem;
if (selectedPerson != null)
{
ExpenseReportPage expenseReportPage = new ExpenseReportPage(selectedPerson);
this.NavigationService.Navigate(expenseReportPage);
}
else
{
MessageBox.Show("请先选择一个人。");
}
}
3.4 报表页(ExpenseReportPage.xaml)
3.4.1 布局与背景
同样使用 Grid,背景相同,但布局略有不同:
xml
<Grid>
<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>
3.4.2 详细信息区域
嵌套 Grid 用于显示姓名、部门和费用表格:
xml
<Grid Margin="10" Grid.Column="1" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- 姓名 -->
<StackPanel Grid.Row="0" Grid.ColumnSpan="2" Orientation="Horizontal">
<Label Style="{StaticResource labelStyle}">Name:</Label>
<Label Style="{StaticResource labelStyle}" Content="{Binding XPath=@Name}"/>
</StackPanel>
<!-- 部门 -->
<StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal">
<Label Style="{StaticResource labelStyle}">Department:</Label>
<Label Style="{StaticResource labelStyle}" Content="{Binding XPath=@Department}"/>
</StackPanel>
<!-- 费用明细表格 -->
<DataGrid Grid.Row="2" Grid.ColumnSpan="2"
ItemsSource="{Binding XPath=Expense}"
AutoGenerateColumns="False"
ColumnHeaderStyle="{StaticResource columnHeaderStyle}">
<DataGrid.Columns>
<DataGridTextColumn Header="ExpenseType" Binding="{Binding XPath=@ExpenseType}"/>
<DataGridTextColumn Header="Amount" Binding="{Binding XPath=@ExpenseAmount}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
3.4.3 代码隐藏(ExpenseReportPage.xaml.cs)
提供自定义构造函数接收数据对象,并将其设置为 DataContext:
csharp
public ExpenseReportPage(object data) : this()
{
this.DataContext = data;
}
这样,页面中的绑定表达式(如 {Binding XPath=@Name})就能自动从传递的 XmlNode 中获取数据。
3.5 资源文件(watermark.png)
将图片添加到项目,生成操作设为"资源",即可在 XAML 中通过相对路径 watermark.png 引用。
如果您手动创建文件,请确保 .csproj 中包含对图片资源的引用。例如:
xml
<ItemGroup>
<Resource Include="watermark.png" />
</ItemGroup>
四、核心概念与实现机制
| 概念 | 在 ExpenseIt 中的应用 |
|---|---|
| XAML | 使用声明式标记定义窗口、页面、控件、布局、样式、数据源等。 |
| 布局 | Grid 实现行列布局,通过 Margin 和 ColumnDefinition/RowDefinition 控制位置与尺寸。 |
| 控件 | Label、ListBox、Button、DataGrid 等构建界面。 |
| 事件处理 | 为按钮添加 Click 事件,通过代码隐藏实现页面导航。 |
| 样式 | 在 App.xaml 中定义全局样式,通过 StaticResource 引用,统一控件外观。 |
| 数据绑定 | 使用 XmlDataProvider 作为数据源,通过 {Binding} 将控件属性绑定到 XML 数据。 |
| 数据模板 | DataTemplate 自定义列表项和表格列内容的呈现方式。 |
| 导航 | NavigationWindow 作为主窗口,通过 NavigationService.Navigate 实现页面切换。 |
| 资源 | 图片作为资源嵌入,XAML 中直接引用。 |
五、运行效果
- 启动程序,显示主页,左侧背景图片,右侧显示人员列表。
- 单击选中一个人(例如 Mike),点击"View"按钮。
- 窗口导航到报表页,显示 Mike 的姓名、部门以及费用明细表格。
- 导航窗口上的后退/前进按钮可返回主页或再次查看报表。
六、学习要点与扩展建议
要点回顾
- WPF 项目模板:正确选择"WPF 应用 (.NET Framework)"模板。
- NavigationWindow:适用于多页面应用,自动提供导航 UI。
- 布局 :
Grid是最常用的布局控件,支持灵活的行列定义。 - 数据绑定 :通过
Binding实现 UI 与数据的解耦,支持 XPath 查询 XML 数据。 - 样式与资源:集中定义样式,提高可维护性。
- 数据模板:用于自定义数据对象的可视化,增强灵活性。
- 事件与导航:处理用户交互,实现页面间数据传递。
扩展建议
- 改用 MVVM 模式 :将数据源和业务逻辑移至 ViewModel,利用
INotifyPropertyChanged实现更清晰的分层。 - 外部数据源 :将 XML 数据替换为数据库(如 SQL Server)或 Web 服务,通过
Entity Framework或HttpClient加载。 - 更丰富的控件 :使用
ComboBox代替ListBox,添加日期选择器等。 - 动画与过渡:为页面导航添加过渡动画。
- 本地化:使用资源字典支持多语言。