1阶段2章笔记 01 WPF项目创建与程序结构了解
第一阶段 · 第二章:WPF 项目创建与程序结构了解
上一篇我们搭好了 Visual Studio 2026 的环境。这一章做两件事:创建一个真正的 WPF 项目,以及看懂这个项目里每个文件都是干嘛的。
一、项目创建:三步走
第 1 步:选模板
打开 Visual Studio,选择 "创建新项目",在搜索框输入 WPF,然后把筛选条件依次设为:
- 语言:C#
- 平台:Windows
- 项目类型:桌面
在筛选后的列表里选中 "WPF 应用程序"(描述:用于创建 .NET WPF 应用程序的项目),点击"下一步"。

⚠️ 最容易踩的坑
列表里还有一个叫
WPF 应用(.NET Framework)的模板,它和我们要选的只差一个括号,但完全是两回事:
模板 运行框架 现状 WPF 应用程序 现代 .NET(.NET 8 / .NET 10) ✅ 选这个,持续更新,能用到新特性 WPF 应用(.NET Framework) .NET Framework 4.x ❌ 旧框架,仅维护,无法升级到现代 .NET 一旦选错,后期想改基本等于重来。判断依据:选中后点"下一步",下一页框架下拉框里显示的应该是
.NET x.0,而不是.NET Framework 4.x。
第 2 步:配置项目名称与位置
进入"配置新项目"页,需要填三个东西:
| 项目 | 示例值 | 说明 |
|---|---|---|
| 项目名称 | App1 |
一个项目(一个程序)的名字 |
| 位置 | D:\Code\WPF\ |
解决方案存放的文件夹 |
| 解决方案名称 | WpfApp |
整个解决方案的名字 |

关于"将解决方案和项目放在同一目录中"这个选项,一般不勾选。
原因是它决定了磁盘上的目录层级:
- 不勾选(推荐):
WpfApp\文件夹 → 里面有.sln文件 +App1\子文件夹 → 子文件夹里才是项目文件。
这样当一个解决方案里放进第二个、第三个项目时,每个项目各占一个平级文件夹,一目了然。D:\Code\WPF\WpfApp\ ← 解决方案文件夹 WpfApp.sln ← 解决方案文件 App1\ ← 项目文件夹 App1.csproj App.xaml MainWindow.xaml - 勾选:
.sln和.csproj挤在同一层。单项目时看着清爽,一旦加第二个项目就会变得混乱。
💡 命名小贴士:项目名和解决方案名尽量用英文(如
WpfApp、App1),路径也尽量避免中文和空格,能省掉后续一堆莫名其妙的编译和打包问题。
第 3 步:选择框架
最后一页是"其他信息",核心是 框架(Framework) 下拉框,没有特殊要求时保持默认即可。

以本次截图为例,默认是 .NET 8.0(长期支持)。
关于版本,记住两点就够了:
- LTS(长期支持):官方标注"(长期支持)"的版本,约支持三年,学习与生产都优先选它;
- STS(标准支持):支持周期较短,适合想尝鲜新特性的场景。
你的 Visual Studio 装了哪些 .NET 版本,这里就列出哪些。如果安装时一并勾选了 .NET 10 组件,这里同样会出现
.NET 10.0(长期支持),选它也没有问题。
点击 "创建",第一个 WPF 项目就诞生了。
二、程序结构:一个项目由哪几部分组成
创建完成后,把视线移到右侧(或左侧)的 解决方案资源管理器,一个 WPF 项目的全貌就在这里。

从结构上看,一个 WPF 项目由 四部分 组成:
App1(项目)
├── 依赖项 ← 这个项目"引用了什么"
├── App.xaml + App.xaml.cs ← 应用程序级别(整个程序)
├── MainWindow.xaml + MainWindow.xaml.cs ← 窗口级别(一个界面)
└── AssemblyInfo.cs ← 程序集特性配置
2.1 依赖项
"依赖项"节点不是磁盘上的真实文件夹,它只是一个逻辑分组,告诉你这个项目用到了哪些外部东西。展开后主要会看到:
| 子节点 | 含义 |
|---|---|
| 框架(Framework) | 最关键的是 Microsoft.WindowsDesktop.App.WPF。它是 WPF 的运行基础,装 VS 时就带上了,不需要自己下载,也别去 NuGet 里手动装 |
| 分析器(Analyzers) | 代码检查工具,编译时会提示潜在问题,不用管它 |
| 包(Packages) | 通过 NuGet 安装的第三方库,装了才会出现 |
| 项目(Projects) | 引用同一解决方案里的其他项目,引用了才会出现 |
编译器报错提示"缺少某某命名空间"时,八成就是这里的依赖项没配好。
2.2 App.xaml —— 整个程序的"总控"
<Application x:Class="App1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:App1"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
它是整个应用程序的入口与配置,可以理解成程序的"开机设置页"。重点看三个地方:
x:Class="App1.App":告诉编译器"这个 XAML 对应的后台类是App1命名空间下的App类"。XAML 和 .cs 文件就是靠这一行配对的,改类名时两边必须同步改,否则编译报错。StartupUri="MainWindow.xaml":程序启动后第一个显示哪个窗口。想让程序启动时打开登录窗口,把这里改成LoginWindow.xaml就行——这是后面做多窗口切换时最常用的一个属性。<Application.Resources>:全局资源区。放在这里的样式、模板、画刷,整个程序的所有窗口都能用。比如你想让所有按钮统一长一个样,样式就写在这里。
开头那几行 xmlns=... 是命名空间声明,不是网址,不会联网。它们的作用是"给一段类型起个别名":
- 不带前缀的默认
xmlns:WPF 的核心控件都在这里(Button、Grid、Window…),所以写<Grid>不用加前缀; xmlns:x:XAML 自身的关键字,凡是x:Class、x:Name这类带x:前缀的都来自它;xmlns:local:指向本项目自己的命名空间App1,这样在 XAML 里就能直接用自己写的类。
2.3 App.xaml.cs —— 程序的后台逻辑
using System.Windows;
namespace App1
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
三个关键点:
partial(分部类):App这个类被拆成了两半——一半是 XAML 编译生成的,一半就是你眼前这个 .cs 文件。两边合起来才是完整的App类。这也是x:Class必须和这里对上的原因。- 继承自
Application:WPF 中所有应用程序的基类,程序的生命周期都由它管。 - 这里看不到
Main方法,也看不到构造函数:因为它们是编译时自动生成的(在obj文件夹下的App.g.cs里)。生成的代码大致做了这么几件事:创建App对象 → 调用InitializeComponent()加载 App.xaml →Run()启动消息循环。这就是为什么我们一个字没写,程序也能跑起来。
补充:笔记里出现的
using System.Configuration;和using System.Data;属于旧框架时代的遗留写法,现代 .NET 的 WPF 模板默认并不生成它们。如果编译时提示找不到,直接删掉即可,不影响程序运行。
App.xaml.cs 后面最常用的三个扩展点,先混个眼熟:
| 写法 | 用途 |
|---|---|
重写 OnStartup |
程序启动时要做的事(读配置、初始化数据库连接、显示登录窗) |
重写 OnExit |
程序退出时要做的事(保存状态、写日志) |
Application.Current |
在任意位置拿到当前这个应用程序对象 |
2.4 MainWindow.xaml —— 一个窗口的界面
<Window x:Class="App1.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:App1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
Window:WPF 的窗口,程序里看到的那个能拖动能关闭的方框就是它。Title="MainWindow":标题栏文字;Height="450" Width="800":初始高宽。注意 WPF 里的单位不是屏幕像素,而是与设备无关的单位(1/96 英寸),所以在高分屏上不会像老程序那样糊掉、缩成一团——这正是 WPF 做界面的优势之一。<Grid>:默认给的根布局容器。Window只能有一个直接子元素,所以通常放一个 Grid,然后在 Grid 里再摆成百上千个控件。xmlns:d和mc:Ignorable="d":这一对是设计时专用的。d:前缀的属性(如d:DesignHeight)只在 Visual Studio 设计器里起作用,用来预览效果;mc:Ignorable="d"则告诉编译器"看到d:开头的就忽略掉",不会编进最终程序。新手完全可以无视它,别被这两行吓到。
2.5 MainWindow.xaml.cs —— 窗口的后台逻辑
namespace App1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
全文最需要记住的只有一行:InitializeComponent();
它的作用是"把 XAML 翻译成真正的界面":读取 MainWindow.xaml,创建出 Grid、Button 等控件对象,安排好层级关系,绑好事件,并给带 x:Name 的控件生成对应的字段。
⚠️ 千万不要删掉它。 一旦删掉,编译也许不报错,但运行时界面一片空白,而且代码里访问任何控件都会得到
null(空引用异常)。这是初学者最经典的"为什么我的按钮是 null"事故源头。
顶部那一长串 using System.Windows.Controls;、using System.Windows.Shapes; 之类,是模板预先把 WPF 常用命名空间都引好了,用到哪个算哪个,不用管。
2.6 AssemblyInfo.cs —— 程序集特性
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, // 主题专用资源字典的位置
ResourceDictionaryLocation.SourceAssembly // 通用资源字典的位置
)]
这个文件声明的是程序集级别的特性,当前唯一的内容是 ThemeInfo,它告诉 WPF:本程序没有按 Windows 主题(浅色/深色)分开的资源字典,通用资源就在本程序集里找。
它是 WPF 项目特有的配置,学习阶段保持原样、完全不用动。真正写样式、做主题时才会回头来改它。
2.7 XAML 与 .xaml.cs 是怎么"配对"的
这是理解 WPF 结构的关键,用一张图说清:
MainWindow.xaml ←→ MainWindow.xaml.cs
x:Class="App1.MainWindow" partial class MainWindow : Window
│ │
└──────── 编译时合并为同一个类 ──────────┘
↓
obj\...\MainWindow.g.cs(自动生成)
里面实现了 InitializeComponent()
要点三连:
x:Class的值 = 后台类的 命名空间 + 类名;- 后台类必须标
partial; InitializeComponent()由编译器生成,不是你写的,但你必须调用它。
2.8 资源管理器里看不到的两个文件夹
解决方案资源管理器显示的是逻辑视图,并不等于磁盘上的真实文件。项目文件夹里还有两个重要目录被默认隐藏了:
| 文件夹 | 作用 |
|---|---|
bin |
编译输出。生成的 .exe 在这里:bin\Debug\net8.0-windows\App1.exe,双击就能直接运行程序 |
obj |
编译中间产物,App.g.cs、MainWindow.g.cs 这些自动生成的文件都在这里 |
想看它们,点一下解决方案资源管理器顶部的 "显示所有文件" 按钮即可。(obj 里的东西不要手改,下次编译会被覆盖。)
三、解决方案与项目的关系
一个解决方案(Solution)可以包含多个项目(Project),关系是 1 对多。

上图这个 WpfApp 解决方案里就同时放着 App1 和 App2 两个 WPF 项目——每个都有自己的 App.xaml、MainWindow.xaml,彼此独立,互不干扰。
关于它们的本质,可以这么理解:
- 从 Visual Studio 的角度看:解决方案的本质是
.sln文件,项目的本质是.csproj文件。这两个文件才是它们的"身份证",里面记录了"我包含哪些项目""我有哪些文件、引用了什么"。删掉这两个文件,VS 就认不出它们了。 - 从磁盘的角度看:解决方案对应一个文件夹,项目也对应一个子文件夹,项目文件夹里放着该项目的所有文件。所以我们能在一个解决方案文件夹里,放多个代表项目的文件夹。
D:\Code\WPF\WpfApp\ ← 解决方案(文件夹 + WpfApp.sln)
├── App1\ ← 项目1(文件夹 + App1.csproj)
└── App2\ ← 项目2(文件夹 + App2.csproj)
顺带纠正一个常见说法:与其说"本质是文件夹",不如说"本质是 .sln / .csproj 文件,它们在磁盘上以文件夹的形式组织"。理解到 .sln 和 .csproj 这一层,后面手动改项目文件、排查引用错误时会轻松很多。
启动项目:一次能启动几个?
一个解决方案里有多个项目,按 F5 时运行哪一个?这就是启动项目(也叫启动项)。
- 默认情况:一个解决方案同一时间只有一个启动项目;
- 怎么切换:最省事的办法是用工具栏上的启动项下拉框直接选。

另外两种常用方式:
- 在解决方案资源管理器里右键某个项目 → "设为启动项目";
- 右键解决方案 → "属性"(或下拉框里的"配置启动项目...")→ 可以设置多个项目同时启动,也可以选择"当前选定内容"(选中哪个项目就运行哪个,调试多项目时非常方便)。
启动项目的名字在工具栏里会显示为加粗,并且下拉列表中带一个对勾,一眼就能看出当前跑的是谁。
四、本章小结
创建项目的三步:选模板(认准不带 .NET Framework 的那个)→ 填名称与位置(默认不勾选"放在同一目录")→ 框架选默认的 LTS 版本。
项目结构的四部分:
| 组成部分 | 一句话记住 |
|---|---|
| 依赖项 | 项目用了哪些外部东西,WPF 框架在这里,不用手动装 |
| App.xaml(.cs) | 整个程序的总控:StartupUri 决定先开哪个窗,Resources 放全局资源 |
| MainWindow.xaml(.cs) | 一个窗口的界面与逻辑,InitializeComponent() 是灵魂,不能删 |
| AssemblyInfo.cs | 程序集特性,当前只有 ThemeInfo,保持原样不动 |
两个原理:XAML 与 .xaml.cs 靠 x:Class + partial 配对;InitializeComponent() 由编译自动生成。
一组关系:解决方案(.sln): 项目(.csproj)= 1 : 多,同一时刻默认只有一个启动项目,可在工具栏一键切换。
本文为个人学习笔记,如有理解偏差之处,欢迎指正交流。
浙公网安备 33010602011771号