资讯动态

WPF 学习周记:从入门到完成一个学生信息管理系统

发布时间:2026/8/24 23:33:24 来源:尧图企业网站定制
本周系统学习了 WPF 的基础知识并动手完成了一个基于 SQL Server 的学生信息管理系统。本文是对本周所学内容的一次梳理也是对这个项目的完整复盘。一、本周学习内容概览本周的学习路线大致是WPF 入门 → 布局 → 样式 → 模板 → 数据绑定 → 数据库访问ADO.NET最后通过一个综合项目把前面所有知识点串了起来。1. WPF 入门WPFWindows Presentation Foundation是微软推出的新一代 GUI 开发框架。相比 WinForm它有几个很关键的特点界面与逻辑分离界面用 XAML 声明式编写业务逻辑用 C# 写在后台前后端耦合度低分辨率无关基于矢量绘图高分辨率下不会出现锯齿硬件加速基于 Direct3D能利用 GPU 渲染数据驱动通过数据绑定实现界面与数据的自动同步而不是像 WinForm 那样手动把数据塞回控件。一个 WPF 项目通常包含App.xaml应用程序本身、MainWindow.xaml主窗体以及对应的.cs后台代码文件。我了解到 Window 窗体有完整的生命周期事件比如Loaded内容加载完成、Closing关闭前、Closed关闭后这在我们后面的项目中启动时加载数据就用到了Loaded事件。2. WPF 布局WPF 中窗口只能包含一个元素所以要把多个控件放进去必须先放一个布局容器。常用容器有容器特点Grid最强大的布局容器按行/列网格布局支持Auto、*按比例等尺寸设置StackPanel元素按水平或垂直方向排成一条直线WrapPanel排满一行后自动换行DockPanel沿边缘停靠最后一个元素填充剩余空间Border不是布局容器而是装饰器用来画边框、背景、圆角这一周我重点掌握了Grid的行列定义、*星号按比例分配空间以及用Border给区域加边框和圆角。项目界面就是靠这些把窗口分割成了四个部分。3. WPF 样式Style当多个控件需要统一外观时不必每个都写一遍属性而是把属性集中定义成一个StyleStyle x:KeyLogin TargetTypeButton Setter PropertyHeight Value70/ Setter PropertyBackground ValueGreen/ /Style还可以用x:Key给样式命名、用BasedOn让样式继承用触发器Trigger实现鼠标悬停变色等交互效果。样式也可以放到资源字典ResourceDictionary里跨窗口复用。4. WPF 模板TemplateControlTemplate控件模板重定义控件的视觉外观比如把一个普通按钮改成圆形按钮、图文按钮DataTemplate数据模板定义数据的呈现形式比如把一个学生对象显示成姓名 专业 学校的一行TemplateBinding模板绑定在控件模板里把控件属性绑定给模板内部元素。我还理解了 WPF 的两棵树逻辑树控件之间的包含关系和可视化树控件内部的视觉结构。5. WPF 数据绑定这是本周最有价值的内容。WPF 是数据驱动 UI核心思想是数据是第一位的UI 是被数据驱动的。绑定语法TextBox Text{Binding Name, ModeTwoWay, UpdateSourceTriggerPropertyChanged} /关键概念DataContext数据上下文给窗体赋值一个 ViewModel内部控件自动共享Path指定绑定数据源的属性路径Mode绑定方向。OneWay只显示、TwoWay双向同步、OneTime只加载一次UpdateSourceTrigger源什么时候更新PropertyChanged实时、LostFocus失焦时。通过ItemsSourceDataTemplate或DataGrid的列绑定一个List集合就能自动生成表格选中行还能通过SelectedItem联动显示详情这就是项目里点击某行显示详情功能的原理。6. 数据库访问ADO.NET与分层数据库用的 SQL Server通过 ADO.NET 的SqlConnection/SqlCommand/SqlDataAdapter访问。我把公共逻辑抽成了一个简单的DBHelperExecuteNonQuery(sql, 参数)增、删、改GetDataTable(sql, 参数)查询返回 DataTable。同时了解了分层思想。我们最终采用了界面层 → BLL 业务层 → DAL 数据访问层 → 数据库的结构配合实体类Model。好处是职责分离界面只管 UI业务逻辑集中在 BLL数据操作集中在 DAL改动一处不影响其他地方。二、项目实战学生信息管理系统1. 需求分析界面从上到下分成四个部分新增区姓名、专业、学校三个输入项 新增按钮数据展示区以表格DataGrid形式展示所有学生数据详情/修改区点击表格某一行自动显示该行详细信息其中学校用下拉框ComboBox选择操作区删除、修改两个按钮。2. 数据库设计数据库名StudentDB表tb_studentCREATE DATABASE StudentDB; GO USE StudentDB; GO CREATE TABLE tb_student( id INT PRIMARY KEY IDENTITY(1,1), -- 编号自增 name NVARCHAR(50) NOT NULL, -- 姓名 major NVARCHAR(50) NOT NULL, -- 专业 school NVARCHAR(50) NOT NULL DEFAULT -- 学校 ); GO INSERT INTO tb_student(name,major,school) VALUES (N张三,N软件工程,N武汉大学), (N李四,N计算机科学,N华中科技大学), (N王五,N信息安全,N武汉大学);3. 架构与目录结构WpfApp1/ Model/StudentModel.cs # 实体类 Util/DBHelper.cs # 数据库辅助类 DAL/StudentDAL.cs # 数据访问层 BLL/StudentBLL.cs # 业务逻辑层 MainWindow.xaml # 界面 MainWindow.xaml.cs # 后台逻辑 App.config # 连接字符串调用链MainWindow.xaml.cs → StudentBLL → StudentDAL → DBHelper → SQL Server4. 核心代码讲解实体类 StudentModel.cspublic class StudentModel { public int Id { get; set; } public string Name { get; set; } public string Major { get; set; } public string School { get; set; } }数据库辅助类 DBHelper.cs精简版public static class DBHelper { static string ConnStr ConfigurationManager.ConnectionStrings[StudentDB].ToString(); ​ // 增、删、改 public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters) { using (SqlConnection conn new SqlConnection(ConnStr)) { conn.Open(); using (SqlCommand cmd new SqlCommand(sql, conn)) { if (parameters ! null) cmd.Parameters.AddRange(parameters); return cmd.ExecuteNonQuery(); } } } ​ // 查询返回 DataTable public static DataTable GetDataTable(string sql, params SqlParameter[] parameters) { using (SqlConnection conn new SqlConnection(ConnStr)) { conn.Open(); using (SqlDataAdapter da new SqlDataAdapter(sql, conn)) { if (parameters ! null) da.SelectCommand.Parameters.AddRange(parameters); DataTable dt new DataTable(); da.Fill(dt); return dt; } } } }用using语句 params参数数组既保证了资源自动释放又让调用代码非常简洁。数据访问层 StudentDAL.cs节选public ListStudentModel GetAllStudent() { ListStudentModel list new ListStudentModel(); DataTable dt DBHelper.GetDataTable(select * from tb_student); foreach (DataRow row in dt.Rows) { list.Add(new StudentModel() { Id Convert.ToInt32(row[id]), Name row[name].ToString(), Major row[major].ToString(), School row[school].ToString() }); } return list; } ​ public void AddStudent(StudentModel s) { string sql insert into tb_student(name,major,school) values(name,major,school); DBHelper.ExecuteNonQuery(sql, new SqlParameter(name, s.Name), new SqlParameter(major, s.Major), new SqlParameter(school, s.School ?? )); }所有 SQL 都使用参数化查询参数而不是字符串拼接这是防止 SQL 注入的基本做法。界面布局 MainWindow.xaml核心部分窗体用 Grid 分成四行分别对应四个区域Grid.RowDefinitions RowDefinition HeightAuto/ !-- 第一行新增区 -- RowDefinition Height*/ !-- 第二行表格占剩余空间 -- RowDefinition HeightAuto/ !-- 第三行详情区 -- RowDefinition HeightAuto/ !-- 第四行操作按钮 -- /Grid.RowDefinitions表格使用 DataGrid列通过 Binding 绑定实体属性DataGrid x:NamedgStudents Grid.Row1 AutoGenerateColumnsFalse IsReadOnlyTrue SelectionChangeddgStudents_SelectionChanged DataGrid.Columns DataGridTextColumn Header编号 Binding{Binding Id} Width60/ DataGridTextColumn Header姓名 Binding{Binding Name} Width*/ DataGridTextColumn Header专业 Binding{Binding Major} Width*/ DataGridTextColumn Header学校 Binding{Binding School} Width*/ /DataGrid.Columns /DataGrid后台逻辑 MainWindow.xaml.cs节选启动时通过Window_Loaded事件加载数据private void Window_Loaded(object sender, RoutedEventArgs e) { LoadData(); } ​ private void LoadData() { dgStudents.ItemsSource bll.QueryAll(); }点击表格某行把选中数据同步到详情区这就是点击某行显示详情private void dgStudents_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (dgStudents.SelectedItem is StudentModel s) { txtId.Text s.Id.ToString(); txtName.Text s.Name; txtMajor.Text s.Major; cboSchool.SelectedItem string.IsNullOrEmpty(s.School) ? null : s.School; } }新增、修改、删除三个按钮分别调用 BLL 的方法操作成功后重新LoadData()刷新表格保证界面与数据库同步private void btnAdd_Click(object sender, RoutedEventArgs e) { if (txtAddName.Text.Trim() || txtAddMajor.Text.Trim() || cboAddSchool.SelectedItem null) { MessageBox.Show(请填写完整的姓名、专业并选择学校); return; } bll.AddStudent(new StudentModel() { Name txtAddName.Text.Trim(), Major txtAddMajor.Text.Trim(), School cboAddSchool.SelectedItem.ToString() }); MessageBox.Show(新增成功); txtAddName.Clear(); txtAddMajor.Clear(); cboAddSchool.SelectedIndex -1; LoadData(); }5. 结果展示6. 踩坑记录写这个项目时也踩了几个坑记录一下按钮 Click 事件绑错删除按钮误绑了修改方法、修改按钮误绑了删除方法运行时点击行为完全反了。教训写完按钮事件一定要核对x:Name、Content、Click三者是否对应忘记加Loaded事件窗体启动后表格一直是空的排查发现是 Window 标签上漏了LoadedWindow_Loaded事件根本没触发校验控件写错新增时校验用的是详情区的输入框而不是新增区的导致校验判断的是错误的控件ConfigurationManager报错WPF 项目默认没有引用System.Configuration程序集需要手动添加引用或者直接把连接字符串写死在 DBHelper 里。三、总结与感想这一周最大的收获是真正理解了 WPF数据驱动 UI的思想。以前写界面总是给控件取名 → 事件里手动赋值现在变成绑定数据 → 数据变界面自己变代码干净了很多。其次是通过这个项目把零散的知识串了起来布局Grid/Border、数据绑定DataGrid Binding、ADO.NETDBHelper 参数化查询、分层架构BLL/DAL/Model每一样都在项目里找到了用武之地。接下来打算继续深入学习一下 MVVM 模式、控件模板的自定义以及把DBHelper换成更完善的 ORM 方案比如 Entity Framework。本文为个人学习记录如有错误欢迎指正。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价