构建C# WinForms仪表盘表单
在C# App From Start to Finish系列的第21课中,Tim Corey专注于在WinForms应用程序中连接锦标赛仪表板表单。 该表单作为应用程序的启动屏幕,作为用户加载现有锦标赛或创建新锦标赛的入口点。 WinForms仪表板是一个利用Windows Forms事件驱动功能的程序,其中用户动作触发由代码处理的特定事件。
Tim解释说,本课不是关于复杂的UI工作,而是关于干净和一致地将数据、模型、存储过程和表单连接在一起。 注意:WinForms特别适用于企业内部软件,如库存管理、CRM系统和会计工具。 要真正理解WinForms仪表板在实际应用中的工作原理,Tim一步一步演示了加载锦标赛、模型实例化、处理数据库连接以及连接UI控件。
在这篇文章中,我们将通过按照Tim的视频解释,按段落跟随,包括时间戳以便于参考,深入了解仪表板表单。 WinForms应用程序通常较轻量级,并提供出色的性能,使其非常适合较旧或性能较低的硬件。
仪表板表单介绍
在一开始,Tim介绍了第21课,并解释了目标:连接锦标赛仪表板表单,这将是应用程序启动时的第一个表单。
Tim指出,该表单故意保持简单。 它只做几件事:
加载现有锦标赛的列表
允许用户选择并加载锦标赛
- 允许用户创建新锦标赛
他向观众保证这将不会是一个冗长或过于复杂的课程,但它确实会涉及系统中的许多重要部分。
仪表板表单的责任
Tim解释了仪表板表单有两个主要责任:
将现有锦标赛加载到下拉菜单中
- 根据用户行为打开其他表单
如果锦标赛已经存在,用户可以选择它并点击加载锦标赛(稍后连接)。 如果用户想创建一个新的锦标赛,他们点击创建锦标赛,这将打开项目中已经存在的表单。
在此时,Tim澄清加载锦标赛按钮尚未连接,稍后课程将处理。
为下拉菜单创建锦标赛列表
选择C#项目模板后,Visual Studio会打开一个表单供您设计用户界面。
Tim切换到表单的代码之后,并解释说下拉菜单需要一个支持列表。注意表单在设计器中出现,准备好UI定制。 由于下拉菜单旨在显示锦标赛,支持列表必须是List< TournamentModel>。
他创建了一个名为tournaments的私有列表,并解释说与其手动创建一个新列表,不如从GlobalConfig连接中获取数据,它抽象了数据源是SQL还是文本文件。
然后,Tim尝试调用一个名为GetTournament_All的方法,注意到它尚不存在,并解释此方法必须添加到数据访问层。
将GetTournament_All添加到数据层
Tim进入SQL连接器并实现了缺失的GetTournament_All方法。 他解释说,该方法将返回一个TournamentModel对象列表。
他复制了项目中其他地方使用的现有模式,并为锦标赛进行了调整。 关键区别在于此方法调用一个名为的存储过程:
spTournaments_GetAllTim解释说该存储过程仅检索基本锦标赛数据:
ID
比赛名称
参赛费
- 活跃状态
他指出,虽然TournamentModel包含更多属性,但这只是第一步。
理解部分模型实例化
Tim暂停解释一个重要概念:部分实例化。
尽管锦标赛模型包括队、奖品和回合,这些属性尚未填充。 在此阶段:
队伍是空的
奖品是空的
- 回合是空的
预期只有基本锦标赛属性在此时被填充,而相关实体如队伍、奖品和回合在进一步加载之前保持空。
Tim强调这是有意的,这些相关实体必须在加载基本锦标赛记录之后填充。
为每个锦标赛填充奖品
Tim引入了一个foreach循环,它对从数据库返回的每个锦标赛进行迭代。
对于奖品,他解释了过程很简单:
调用一个存储过程,根据锦标赛ID检索奖品
- 将结果赋值给T.Prizes
他引用了存储过程spPrizes_GetByTournament,并解释说它返回与给定锦标赛相关的所有奖品。
这种模式——加载基础数据,然后通过ID加载子数据——是Tim在整个应用程序中反复强调的内容。
加载队伍和队员
接下来,Tim转向参赛队伍。
他解释说加载队伍是一个两步过程:
加载与锦标赛相关的队伍
- 对于每个队伍,加载队员
他使用名为spTeams_GetByTournament的存储过程来检索与当前锦标赛相关的队伍。
然后,对于每个队伍,Tim复用一个现有方法按队伍ID加载队员。 他指出这几乎与系列中先前编写的代码相同,只是针对锦标赛特定数据进行了调整。
介绍回合的复杂性
Tim解释说,回合是锦标赛模型中最复杂的部分。
回合存储为:
List<List<MatchupModel>>要填充它们,Tim需要:
加载锦标赛的所有对战
为每个对战加载对战条目
- 解决关系如父对战和胜者
他从查看存储过程开始:
spMatchups_GetByTournament
- spMatchupEntries_GetByMatchup
处理获胜者ID和嵌套模型
Tim指出使用数据库时的一个常见问题: SQL返回ID,但应用程序期望对象。
Winner属性是一个TeamModel,但数据库只返回WinnerId。 Tim解释你不能直接从SQL实例化嵌套对象。
为了解决这个问题,他在模型中添加一个临时WinnerId属性,仅在数据加载期间使用。 一旦所有队伍加载完成,他使用ID赋给Winner属性正确的TeamModel。
填充对战条目和父对战
对于每个对战,Tim:
根据对战ID加载对战条目
检查有效的队伍ID
- 使用缓存的所有队伍列表解决关系
他解释为什么在没有值时ID默认为0,以及为什么>0检查是必要的。
Tim还解释如何通过引用已经加载的对战解析父对战,依靠对战按回合排序的事实。
构建回合结构
一旦所有对战完全填充,Tim解释如何构建回合。
他介绍:
一个currentRound变量
- 一个currentRow列表
当他循环对战时:
如果回合号改变,之前的回合被添加到T.Rounds
创建一个新回合列表
- 相应地分组对战
Tim通过一个完整示例确保逻辑清晰,并强调分开循环使代码更容易理解。
连接仪表板下拉菜单
您可以通过在Visual Studio工具箱中拖动标签、文本框和下拉菜单等常用控件到表单来添加。
回到仪表板表单,Tim创建一个WireUpLists()方法。
他分配:
DataSource给锦标赛列表
- DisplayMember给TournamentName
标签通常用于描述下拉菜单的用途,而文本框可用于表单中的用户输入。 要处理用户交互,您可以在设计器中双击按钮以自动生成Form1.cs文件中的单击事件处理程序。
他解释了这是使下拉菜单显示人类可读名称而不是对象引用的原因。
测试SQL和文本文件连接
Tim使用两种数据源运行应用程序:
文本文件连接立即起作用
- SQL连接抛出错误
您可以通过选择启动按钮或在Visual Studio中按F5来执行应用程序。
他分析错误信息,识别出由于缺少参数导致此错误,并指出在集成多种数据源时此类错误很常见。 这个错误通过正确传递锦标赛ID给存储过程被修复。
在修复奖品和队伍后,Tim确认两种数据源现在都能正常工作。 识别和修复错误是开发过程中的正常组成部分,尤其是在集成多种数据源时。
连接创建锦标赛按钮
最后,Tim通过处理事件,特别是单击事件连接了创建锦标赛按钮。
他解释写入按钮事件处理代码是在代码背后文件(Form1.cs),而不是在Form1.Designer.cs文件。Form1.Designer.cs文件自动生成Windows Forms的UI代码,不应手动编辑。
按钮简单地:
创建创建锦标赛表单的新实例
- 调用Show()
他讨论用户创建锦标赛后应去哪里,并解释为何直接导航到锦标赛查看器最为合理。
结论和下一步
Tim总结所做的工作:
仪表板加载锦标赛
下拉菜单正确填充
- 成功打开创建锦标赛表单
他指出,创建锦标赛后刷新列表将在稍后处理。
在下一个课程中,Tim预览锦标赛查看器表单,其中将实现回合、对战、评分和进展——使锦标赛系统变得栩栩如生。未来版本的此课将涵盖包括与新版本WinForms和.NET相关的更新的更多特性和改进。
这个课程展示了一个WinForms仪表板不仅仅是一个UI,而是一个模型、数据接入和导航间的协调点——Tim一步一步仔细演示。
WinForms因其稳定性、快速开发速度以及与Windows操作系统的深度整合而仍然具高度相关性。

