WPF-03 第一个WPF程序

文章目录

    • [第一个 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 实现行列布局,通过 MarginColumnDefinition/RowDefinition 控制位置与尺寸。
控件 LabelListBoxButtonDataGrid 等构建界面。
事件处理 为按钮添加 Click 事件,通过代码隐藏实现页面导航。
样式 App.xaml 中定义全局样式,通过 StaticResource 引用,统一控件外观。
数据绑定 使用 XmlDataProvider 作为数据源,通过 {Binding} 将控件属性绑定到 XML 数据。
数据模板 DataTemplate 自定义列表项和表格列内容的呈现方式。
导航 NavigationWindow 作为主窗口,通过 NavigationService.Navigate 实现页面切换。
资源 图片作为资源嵌入,XAML 中直接引用。

五、运行效果

  1. 启动程序,显示主页,左侧背景图片,右侧显示人员列表。
  2. 单击选中一个人(例如 Mike),点击"View"按钮。
  3. 窗口导航到报表页,显示 Mike 的姓名、部门以及费用明细表格。
  4. 导航窗口上的后退/前进按钮可返回主页或再次查看报表。

六、学习要点与扩展建议

要点回顾
  • WPF 项目模板:正确选择"WPF 应用 (.NET Framework)"模板。
  • NavigationWindow:适用于多页面应用,自动提供导航 UI。
  • 布局Grid 是最常用的布局控件,支持灵活的行列定义。
  • 数据绑定 :通过 Binding 实现 UI 与数据的解耦,支持 XPath 查询 XML 数据。
  • 样式与资源:集中定义样式,提高可维护性。
  • 数据模板:用于自定义数据对象的可视化,增强灵活性。
  • 事件与导航:处理用户交互,实现页面间数据传递。
扩展建议
  • 改用 MVVM 模式 :将数据源和业务逻辑移至 ViewModel,利用 INotifyPropertyChanged 实现更清晰的分层。
  • 外部数据源 :将 XML 数据替换为数据库(如 SQL Server)或 Web 服务,通过 Entity FrameworkHttpClient 加载。
  • 更丰富的控件 :使用 ComboBox 代替 ListBox,添加日期选择器等。
  • 动画与过渡:为页面导航添加过渡动画。
  • 本地化:使用资源字典支持多语言。

相关推荐
智在碧得2 小时前
碧服智能体进化:AI赋能意图识别能力,“一问”更智能
大数据·人工智能·机器学习
蓝天守卫者联盟13 小时前
如何选择二氯甲烷回收设备厂家:技术路线与市场格局深度解析
大数据·人工智能·python·sqlite·tornado
xiaoduo AI3 小时前
客服机器人能否支持自动排班与请假?Agent 系统支持人员替班,夜间无人值守该如何应
大数据·人工智能·机器人
紧固视界3 小时前
2026上海紧固件专业展,紧固件设备集中展示平台
大数据·人工智能·上海紧固件展·紧固件展·上海紧固件专业展
DevOpenClub3 小时前
全国三甲医院主体信息 API 接口
java·大数据·数据库
大喵桑丶4 小时前
ZABBIX7二次开发AI监控数据调取杂记
大数据·人工智能·python
DX_水位流量监测4 小时前
德希科技在线多参数七参传感器使用说明
大数据·水质监测·水质传感器·水质厂家·供水水质监测·在线多参数水质分析仪·水质七参
光电大美美-见合八方中国芯4 小时前
用于无色波分复用光网络的 10.7 Gb/s 反射式电吸收调制器与半导体光放大器单片集成
网络·后端·ai·云计算·wpf·信息与通信·模块测试
晓纪同学4 小时前
WPF-02体系结构
wpf