跳至页脚内容
Iron Academy Logo
C# 应用程序
C# 应用程序

其他类别

将C# WinForms锦标赛数据保存到数据库中 — 深度剖析Tim Corey

Tim Corey
2h 32m 16s

在"C# App From Start to Finish"系列的第19课中,Tim Corey演示了项目的一个重要里程碑:将一个完全构建的WinForms比赛保存到数据库(和文本文件)。 WinForms是一个构建Windows桌面应用程序的框架,非常适合在真实世界背景下展示数据持久性。

这篇文章完全基于第19课 – 创建比赛表单(第5部分),遵循了Tim自己的逐步推理、调试流程和编码模式。

与其呈现理论,Tim通过真实的应用程序代码展示了模型如何被保存、重新加载、调试和纠正,当事情不可避免地出错时。 这使得该课程特别有价值,以理解WinForms中的实用数据持久性。

简介

在一开始,Tim介绍了第19课并解释今天终于完成了创建比赛表单。 他承认这个表单迄今为止是最大的之一,有许多移动部件可能让人感到不知所措。 在这一课中,您将学习如何应用WinForms的事件驱动模型和快速应用程序开发功能来完成一个真实世界的表单。

Tim安慰观众,复杂性已经分解成可管理的部分,今天的重点是为保存比赛数据所需的最终逻辑——无论是SQL数据库还是文本文件——然后这个功能就完成了。 WinForms非常适合快速应用程序开发(RAD)和构建内部业务工具或轻量级实用程序,其相对简单的事件驱动模型和大量的在线资源使新开发人员更易于学习。

在 Visual Studio 中创建新项目

使用Visual Studio开始Windows Forms应用程序既简单又直接。 首先打开Visual Studio并从启动窗口中选择"创建新项目"。 在"创建新项目"对话框中,使用搜索栏键入"Windows Forms App"——这会迅速显示您需要的模板。 要缩小选项范围,可以按C#作为语言和Windows作为平台进行过滤。

一旦找到"Windows Forms App (.NET Framework)"项目类型,选择它并点击下一步。 在"配置新项目"窗口中,给项目命名(例如,HelloWorld),选择位置,然后单击创建。 Visual Studio将生成一个新的解决方案并打开您的主要表单,该表单作为您应用程序的图形用户界面。 这个表单是您设计用户界面和添加控件的地方,为您的Windows桌面应用程序打下基础。 该模板包含所有必要的文件和对.NET Framework的引用,因此您可以立即专注于构建应用程序的功能和特性。

审查创建比赛按钮的逻辑

Tim从一次审查开始。 他解释说,程序中的一切都从创建比赛按钮开始。 在C# WinForms程序中,为事件处理程序编写代码以响应特定用户操作,如点击创建比赛按钮。 截至目前,应用程序已经:

  • 验证用户输入

  • 构建比赛对象

  • 在内存中创建回合和比赛

Tim解释,缺失的一环是维持这些数据。 以前,应用程序可以保存比赛、奖品和条目——但缺少回合信息。 这就是本课程解决的问题。

在SQL中保存比赛:大局观

Tim导航到SQL连接器的CreateTournament方法,并提醒观众保存数据遵循一个清晰的模式:

  1. 保存比赛本身

  2. 获取比赛ID

  3. 保存奖品

  4. 保存参赛项

  5. 现在:保存轮次和对阵表

注意:遵循这个保存顺序非常重要,以确保所有相关数据被正确关联,并维持应用程序的数据完整性。

Tim强调模式的好处,本课程遵循了之前建立的同样模式。

WinForms还支持创建可重用的UI元素,如按钮、文本框和标签,这有助于维护应用程序数据结构的一致性。

理解数据结构复杂性

在这里,Tim暂停解释为什么保存轮次更复杂。

  • 一个比赛有多个轮次

  • 每个轮次都是一个MatchupModel的列表

  • 每个对阵包含MatchupEntryModel对象

Tim解释这是列表中的列表,在这个阶段这样的复杂性是正常的。 他鼓励观众不要恐慌—这只是建模真实世界数据的自然结果。

他还提到WinForms应用程序是使用组件构建的,如数据网格和UI控件,这帮助开发者高效地创建功能丰富的桌面应用程序。 Windows Forms类库中的所有视觉元素都派生自Control类,为构建和自定义用户界面提供了一个一致的基础。

为何保存顺序很重要

视频中最关键的解释之一就发生在这里。

Tim解释数据必须按顺序保存,因为:

  • 一个对阵项在其父对阵ID存在之前不能被保存

  • 一轮次不能引用下一轮次,直到前一轮次已有ID

他解释由于对象引用同一内存地址,一旦ID在一个地方填充,所有引用都会自动更新。 然而,开发者可能需要在分配ID时修改对象引用,这是C# WinForms应用中事件驱动过程的典型部分,其中应用程序响应用户操作和数据更改。

确保所有模型都有ID

Tim指出一个重要的修复:MatchupEntryModel尚未有一个ID属性。

即使当前并不立即需要,Tim也加入了它,解释说每个数据库支持的模型都应该有一个ID以保持一致性和未来使用。 默认情况下,Windows Forms应用程序使用如Form1.Designer.cs这样的文件自动生成UI代码,确保应用程序的标准结构和行为。

将逻辑分解为简单步骤

本节为在C WinForms应用程序中保存数据提供了一个教程。

Tim使用了他最喜欢的教学类比之一:像吃大象一样一步一步来。

他将保存逻辑分成了明确的步骤:

  1. 循环遍历每一轮次

  2. 在每一轮次内循环遍历对阵

  3. 保存每个对阵

  4. 循环遍历对阵项

  5. 保存每个项

每个步骤本身都很简单—而且合在一起,它们很强大。

Visual Studio中的简单的拖放视觉设计器使WinForms非常适合构建内部工具、原型和简单应用程序。

循环遍历轮次和对阵

Tim显示如何循环遍历一个轮次列表,其中每个轮次本身是一个MatchupModel列表。

他一开始故意避免使用var,并解释了原因:显式类型帮助开发者理解他们在循环什么,特别是在处理嵌套列表时。 在Windows Forms开发中使用不同编程语言时,清晰的代码尤其重要,因为它提高了可维护性并支持多语言的本地化。

他也分享了一个重要的哲学:

"最好的代码是初级开发者也能理解的代码。"

Windows Forms应用程序是事件驱动的,并且由微软的.NET提供支持。

创建对阵插入存储过程

Tim切换到SQL并创建了spMatchups_Insert。

他清楚地解释了字段:

  • 比赛ID

  • 对阵轮次

  • 胜利者ID(可为空)

可包含附加字段,如日期,以便跟踪对阵何时进行。

Tim故意在此阶段没有设定胜利者。 即使一个对阵是轮空,他更倾向于使用与真实比赛相同的逻辑更晚处理胜利者。

Windows Forms通过在托管代码中包装现有Windows API提供对本机Windows用户界面常用控件的访问。

保存对阵项并处理NULL值

Tim创建了另一个存储过程:spMatchupEntries_Insert。

他解释:

  • 分数为NULL是因为比赛尚未进行

  • NULL不等同于零

  • 在后续轮次中TeamCompeting可以为NULL

他用一个令人难忘的例子结合足球和高尔夫解释为什么零是一个真实的值,而NULL表示值不存在。

可以在您的Windows Forms项目中配置应用程序设置以处理不同的数据场景,如NULL值在控件中如何显示或处理。

Windows Forms作为Microsoft .NET、.NET Framework或Mono的一部分。

.NET Framework应用程序的特性和功能

在.NET Framework上构建的Windows Forms应用程序为创建现代Windows桌面应用程序提供了强大的功能集合。 通过Windows Forms(WinForms),您可以访问丰富的图形用户界面(GUI)库,轻松设计直观的交互式用户界面。 WinForms是一个免费的开源框架,包括在Microsoft .NET、.NET Framework和Mono中,通过托管代码实现与本机Windows控件和Windows API的无缝集成。

Visual Studio IDE通过提供Windows Forms Designer这样的大量工具增强了开发体验,使您可以直接将常用控件(例如按钮、文本框和标签)拖放到您的表单上。 这种可视化的设计方法加速了UI设计,并允许您使用属性窗口自定义属性和事件。 结合对代码编辑、调试和项目管理的内置支持,Visual Studio简化了构建、测试和完善Windows桌面应用程序的过程。 无论您是创建商务工具、实用程序还是教育软件,.NET Framework和WinForms提供了一个强大的平台,可以交付功能丰富、响应迅速且用户友好的应用程序。

使用编辑并继续进行调试

当异常发生时,Tim不惊慌,他进行教学。

他使用Visual Studio的编辑并继续功能来:

  • 暂停执行

  • 插入空检查

  • 恢复执行而不重新启动应用程序

键盘快捷键,如使用'Ctrl'组合(例如,'Ctrl + Alt + X'打开工具箱),可以加快调试速度和在Visual Studio中访问UI控件。

他展示了如何:

  • 检查TeamCompeting是否为空

  • 传递NULL给SQL而不是访问.ID

  • 将相同的逻辑应用于ParentMatchup

这是真实的调试工作流程,完全如同Tim所使用的。

Visual Studio为C#开发提供了广泛的功能和工具,包括Windows Forms Designer。

验证SQL中的数据

修复了两个小错误后,Tim查询数据库。

他确认:

  • 对阵被正确保存

  • 轮次数字准确

  • 轮空逻辑有效

  • 父子关系是正确的

注意在保存后,数据库中的正确关系和数据,因为这一视觉反馈对验证应用程序逻辑是否按预期工作很重要。

Tim指出在一个非常复杂的功能中仅发生了两个错误,并将成功归功于计划、模式和将工作分解成小块。

Windows Forms提供了一个平台来为桌面、笔记本电脑和平板电脑编写客户端应用程序,使其成为Windows开发的多用途选择。

编译和准备查找方法

Tim开始确保项目在解决未完成部分前仍然可以编译。 在1:17:08,他解释说系统将字符串传入方法,并接收一个或多个MatchupEntryModel对象作为返回,从文本文件中提取。

在1:17:40,Tim实现了一个名为LookupTeamById(int id)的方法。 他解释当数据存储在文本文件中时,只保存ID,而不是完整对象。 因此,当加载数据时,应用程序必须将该ID恢复为一个完整的TeamModel。

Tim指出这不是新逻辑—他只是重用了已用于从文件加载所有团队的相同模式。他强调这种重用是有意的,也是正确代码结构的核心优势之一。 开发者还可以查阅现有方法和官方文档,以获取在实现类似逻辑时的额外指导。

Windows Forms被认为是用于GUI开发的早期且更复杂的基于C++的Microsoft Foundation Class库的替代品。

通过GlobalConfig集中管理文件路径

在1:20:27,Tim暂停并指出一个设计问题:文件名到处传递,尽管它们是常量。 他公开表示这感觉"荒谬"。

为了解决这个问题,Tim将文件名常量移入GlobalConfig,并使它们公开。 在1:21:33,他解释说这样可以避免通过多个层次的方法传递文件路径。 Visual Studio中的解决方案资源管理器有助于管理这些项目文件和整体结构,使查找和更新此类常量变得更加简单。

然而,在1:22:24,Tim对一个缺陷实话实说:这些常量现在存在于两个地方—GlobalConfig和TextConnector。 他明确表示这违反了DRY(不要重复自己)原则,并指出这应该在稍后重构,但今天不是那一天。

还需要注意的是,Windows Forms不提供像Microsoft Foundation Class(MFC)这样默认的应用程序框架。

将字符串转换为对阵项模型

在1:24:37,Tim开始实现ConvertStringToMatchupEntryModel。 他解释说对阵项被存储为管道分隔的ID,所以第一步是以管道分隔符拆分字符串(|). 与使用页面作为主要UI容器进行导航和布局的Web应用程序不同,WinForms使用表单来组织用户界面。

到1:25:17,他循环遍历每个ID,从对阵项文件中查找,并将相应的模型添加到输出列表中。模式仍然一致:

加载 → 转换 → 按ID过滤 → 返回模型

Tim强调一致性使得调试在以后变得可能。

Windows Forms应用程序可以使用.NET编程语言开发,如C#或Visual Basic。

构建ConvertToMatchupEntryModels扩展

在1:27:56,Tim创建了一个扩展方法ConvertToMatchupEntryModels(List< string>)。 为指导过程,他复制了一个现有的转换方法(用于PersonModel),并仅将其用作模式参考。

到1:30:28,Tim显式映射了列:

  • 列0 → ID

  • 列1 → TeamCompeting ID

  • 列2 → 分数

  • 列3 → ParentMatchup ID

他解释存储的值只是一个ID,因此完整对象必须使用查找方法重新构建。 WinForms中的某些UI组件和主题灵感来源于Microsoft Office,如Office 2019彩色和Office 2019黑色,以提供一个熟悉的用户体验。

第三方供应商如DevExpress提供全面的WinForms UI组件套件。

安全处理父级对阵

在1:38:49,Tim发现了一个重大问题:父级对阵可能不存在(尤其是在第一轮)。 对缺失的ID调用First()将导致应用程序崩溃。

在1:39:09,他的修复使用int.TryParse。 如果解析失败,ParentMatchup被设置为null。 Tim仔细解释这是第一轮对阵正应该发生的。 每次发行WinForms或第三方库时,通常包含新功能和修复,改进此类情景的处理方式。

他强调崩溃只有在无效数据不应该存在时才可接受,如无效的团队ID。

DevExpress WinForms订阅包含超过190个UI控件和库,提供了构建强大应用程序的广泛选项。

将对阵和对阵项保存到文件中

在1:44:00,Tim进入数据保存。 他加载所有对阵,确定下一个可用ID,分配它,然后转到保存对阵项。 保存数据后,您可以通过点击开始按钮或在Visual Studio中按F5运行您的WinForms应用程序来测试应用程序。

到1:46:44,Tim强调可重用方法的威力—加载和转换文件现在变得"无聊",他表示这是件好事。

他首先保存对阵项目,以便每个项目获取一个ID,然后保存对阵本身,这些对阵存储为用管道分隔的字符串的项目ID。

此外,DevExpress WinForms订阅包括一个带有最终用户报表设计器的报表套件,可以增强您的WinForms应用程序。

将对阵项目写入数据库

在1:49:43,Tim逐步构建保存逻辑。他仔细地反转了早期的转换模式:

  • ID

  • TeamCompeting ID(或空字符串)

  • 得分

  • ParentMatchup ID(或空字符串)

在解释保存逻辑后,重要的是要注意,WinForms支持各种.NET平台,确保兼容性和持续更新。

在1:52:02,Tim解释了为什么空字符串是必需的:它们在不破坏解析逻辑的情况下保持列顺序。

此外,DevExpress WinForms控件支持DirectX硬件加速,以提高性能。

保存对阵和胜者

在1:55:02,Tim保存对阵本身。 因为对阵可以有多个项目,他使用一个重复利用的助手方法将项目列表转换为用管道分隔的字符串。 开发者可以使用Visual Studio中的工具箱来添加像按钮和标签这样的控件到他们的Windows窗体中,以便更易于设计用户界面。

在1:58:30,他对胜者字段应用了同样的空值处理逻辑。 如果还没有胜者,则保存一个空字符串。

Windows窗体使开发者能够为桌面、平板和PC创建应用程序。

加载比赛时重新构建回合

在2:02:03,Tim处理最终的TODO:加载回合信息。 他解释说,回合作为对阵ID列表存储,首先用管道分隔,然后用插入符号(^)分隔。

到2:09:13,他重构了完整的嵌套结构:

  • ID → MatchupModels

  • MatchupModels → 回合列表

  • 回合列表 → TournamentModel

在解释完重构后,Tim指出,与其他一些框架不同,WinForms使用了一种不同的方法来组织UI和数据,这可能会影响开发者如何管理嵌套结构。

Tim强调说,这种嵌套解释了为什么代码感觉复杂——以及为什么手动逐步理解代码非常重要。

此外,值得一提的是,DevExpress WinForms订阅包括可定制的主题和皮肤,适用于WinForms应用程序。

调试真实错误

从2:11:22开始,Tim故意运行应用程序并调试:

  • NullReferenceException

  • 输入字符串格式不正确

  • 序列不包含元素

Tim没有掩盖错误,而是精准展示了如何追踪这些错误,检查值,并推理执行顺序。 WinForms多年前首次发布,并随着时间的推移不断演变。

在2:20:30,他识别出一个循环保存问题:对阵需要先存在,才能被项目引用。 他的解决方案是务实的——保存两次。他坦诚承认这并不优美,但表示:

*"可运行的代码胜过带有问题的重构代码。"

Windows窗体现在作为.NET Core的开源项目在GitHub上提供。

部署Windows窗体应用程序

在Visual Studio中构建和测试您的Windows窗体应用程序后,下一步是部署——让您的应用程序可供用户使用。 Visual Studio 提供了几种部署选项,而ClickOnce是Windows桌面应用程序最方便的一种。 ClickOnce允许您将应用程序发布到网络文件共享、网络服务器,甚至是CD/DVD,使最终用户安装变得简单。

要部署,您只需使用Visual Studio中的发布工具来打包您的应用程序。在发布前,务必使用Visual Studio的调试工具对应用程序进行彻底测试,以捕捉和修复代码中的任何错误或问题。 一旦部署,用户可以通过运行设置文件或点击快捷方式来安装您的应用程序,应用程序将执行并显示其图形用户界面以供直接交互。 无论您选择ClickOnce、Windows Installer还是其他第三方部署工具,确保您的用户可以轻松获取Windows窗体应用程序的完整功能和特性是整个过程的目标。 这种简化的部署过程帮助您将可靠、专业的Windows桌面应用程序提供给您的观众。

结束思考

在这个课程结束时,Tim Corey展示了一个完整的、可运行的数据持久性系统,使用文本文件作为数据库。 更重要的是,他展示了真实世界的错误如何出现,模式如何指导修复,以及为什么理解执行顺序比完美更重要。

这节课不是关于花哨的数据库,而是关于如何像开发者一样思考。

Hero Worlddot related to 将C# WinForms锦标赛数据保存到数据库中 — 深度剖析Tim Corey
Hero Affiliate related to 将C# WinForms锦标赛数据保存到数据库中 — 深度剖析Tim Corey

分享您的所爱,赚取更多收入

您为使用 .NET、C#、Java、Python 或 Node.js 的开发人员创建内容吗?将您的专业知识转化为额外收入!

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我