將C# WinForms比賽資料保存到資料庫 - 深入探討 Tim Corey
[[academy-video-youtube({"vid": "rm1Avf5XJw8", "start_time": "0", "title": "C# App Start To Finish Lesson 19 - Create Tournament Form Part 5", "creator": "Tim Corey", "length": "2h 32m 16s"})]]
在"C# App From Start to Finish"系列的第19課中,Tim Corey介紹了專案中的一個重要里程碑:將完整構建的WinForms比賽保存到資料庫(和文字文件)中。 WinForms是一個用於構建Windows桌面應用程式的框架,這使其成為演示在真實環境中資料持久化的理想選擇。
本文完全基於課程19 – 建立比賽表單(第五部分),並遵循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方法,並提醒觀眾保存資料遵循清晰的模式:
保存比賽本身
獲取比賽ID
保存獎品
保存參賽作品
- 現在:保存回合和比賽
注意:按照這個保存順序很重要,以確保所有相關資料正確關聯,並維護應用的資料完整性。
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使用他最喜歡的教學類比之一:一口一口地吃掉一頭大象。
他將保存邏輯分解為清晰步驟:
遍歷每個回合
在每個回合內,遍歷比賽
保存每場比賽
遍歷比賽項目
- 保存每個項目
每一步本身都很簡單——但結合在一起,它們非常強大。
Visual Studio中直觀的拖放式設計器,使WinForms非常適合構建內部工具、原型和簡單應用程式。
遍歷回合和比賽
Tim展示了如何遍歷一個回合列表,其中每個回合本身都是MatchupModel的列表。
他故意不使用var,並解釋原因:明確的型別幫助開發者理解他們正在遍歷什麼,特別是在處理巢狀列表時。 清晰的程式碼在Windows Forms開發中特別重要,因為它提高了可維護性並支持多語言的本地化。
他還分享了一個重要的理念:
"最好的程式碼是初級開發者能理解的程式碼。"
Windows Forms應用是事件驅動的,由微軟的.NET Framework支持。
建立比賽插入儲存過程
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作為微軟.NET、.NET Framework或Mono的一部分提供。
.NET Framework應用的特性和功能
基於.NET Framework構建的Windows Forms應用提供了一套強大的特性,用於建立現代Windows桌面應用程式。 使用Windows Forms(WinForms),您可以存取豐富的圖形使用者介面(GUI)庫,這使得設計直觀和交互式的使用者介面變得簡單易行。 WinForms是一個免費的開源框架,與微軟.NET、.NET Framework和Mono一起提供,可以通過託管程式碼無縫整合到本地的Windows控件和Windows API中。
Visual Studio IDE增強了您的開發體驗,提供如Windows Forms設計器等工具,允許您直接拖放常見控件(如按鈕、文字框和標籤)到您的表單上。 這種視覺方法加快了UI設計,並允許您使用屬性窗口自定義屬性和事件。 借助內建的程式碼編輯、除錯和專案管理支持,Visual Studio使構建、測試和完善您的Windows桌面應用程式的過程更流暢。 不管您是在建立商業工具、實用程式還是教育軟體,.NET Framework和WinForms都提供了一個堅固的平台,用於交付功能豐富、反應迅速且對使用者友好的應用程式。
使用Edit and Continue進行除錯
當出現異常情況時,Tim不慌張,他進行教學。
他使用Visual Studio的Edit and Continue功能來:
暫停執行
插入NULL檢查
- 無需重啟應用就能恢復執行
鍵盤快捷鍵,如使用'Ctrl'組合(例如,'Ctrl + Alt + X'來打開工具箱),可以加快除錯和存取Visual Studio中的UI控件。
他展示如何:
檢查TeamCompeting是否為NULL
將NULL傳遞給SQL,而不是存取.ID
- 將相同邏輯應用於ParentMatchup
這是真實世界的除錯工作流程,正如Tim所使用的一樣。
Visual Studio為C#開發提供了廣泛的功能和工具,包括Windows Forms設計器。
在SQL中驗證資料
修復兩個小故障後,Tim查詢了資料庫。
他確認:
比賽保存正確
回合號準確
輪空邏輯有效
- 父子關係正確
注意保存後資料庫中的正確關係和資料,因為這種視覺反饋對於驗證應用邏輯是否按預期運行很重要。
Tim指出,在極其複雜的功能中,只有兩個錯誤發生——他將成功歸功於規劃、模式和將工作分解為小部分。
Windows Forms提供了一個平台,可以為桌上、筆記型電腦和平板電腦撰寫使用者端應用,是Windows開發的多用選擇。
編譯和準備查找方法
Tim首先確保專案仍能編譯,然後再處理未完成的部分。 在1:17:08,他解釋系統會將字串傳入方法,並根據文字文件返回一個或多個MatchupEntryModel物件。
1:17:40時,Tim實現了一個方法叫LookupTeamById(int id)。 他解釋說,當資料儲存在文字文件中時,只保存ID,而不是完整的物件。 因此,當載入資料時,應用需要將該ID恢復為完整的TeamModel。
Tim指出,這不是新邏輯——只是重用之前為載入所有團隊所用的相同模式。他強調,這種重用是有意的,結構正確程式碼的核心優勢。 開發者也可以查閱現有方法和官方文件,以便在實現類似邏輯時獲得額外指導。
Windows Forms被視為取代早期且更複雜的基於C++的微軟基礎類庫(MFC)進行GUI開發的選擇。
使用GlobalConfig集中管理文件路徑
1:20:27時,Tim暫停並指出一個設計問題:文件名被傳遞至所有地方,儘管它們只是常量。 他直言不諱地說,這感覺"荒謬"。
為了解決這個問題,Tim將文件名常量移到GlobalConfig中,並設為公開。 在1:21:33,他解釋這樣避免了根據多層方法傳遞文件路徑。 Visual Studio中的解決方案管理器有助於管理這些專案文件和整體結構,讓查找和更新這些常量變得更容易。
然而,1:22:24時,Tim對一個缺陷坦率:這些常量現在存在於兩個地方—GlobalConfig和TextConnector中。 他明確稱這為DRY(不要重複自己)原則的違反,並指出應該在稍後進行重構,但今天不在計劃之內。
還需要注意到,Windows Forms並未提供預設的應用程式框架,如微軟基礎類(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→Score
- 欄3→ParentMatchup ID
他解釋,儲存值僅是ID,所以必須使用查找方法重建完整的物件。 WinForms中的一些UI組件和主題受到微軟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 Forms,以便於設計使用者介面。
1:58:30時,他對獲勝者字段應用了相同的空值處理邏輯。 如果尚無獲勝者,將保存一個空字串。
Windows Forms使開發人員能夠為桌上型電腦、平板電腦和PC建立應用程式。
載入比賽時復原回合
2:02:03時,Tim處理最後一項待辦事項:載入回合資訊。 他解釋回合作為比賽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,他發現了一個迴圈保存問題:在條目可以引用之前需要已存在比賽。 他的解決方案是務實的——保存兩次。他坦誠地表達,雖然不優雅但表達道:
"工作中的程式碼優於仍有bug的重構程式碼。"
Windows Forms現作為一個開源專案,供.NET Core在GitHub上使用。
部署一個Windows Forms應用程式
在Visual Studio中構建和測試您的Windows Forms應用程式後,下一步是部署——使您的應用對使用者可用。 Visual Studio提供多種部署選項,以ClickOnce是Windows桌面應用中最方便的之一。 ClickOnce允許您將應用發佈到網路文件共享、Web伺服器甚至CD/DVD,使安裝對最終使用者來說簡單易行。
為了部署,只需使用Visual Studio中的發佈工具打包您的應用。在發佈之前,使用Visual Studio的除錯工具徹底測試您的應用程式,以捕捉修復任何程式碼中的錯誤或問題。 一旦部署,使用者可以通過運行安裝文件或單擊快捷方式來安裝您的應用,應用將執行,顯示其圖形使用者介面以進行即時互動。 無論您選擇ClickOnce、Windows Installer還是第三方部署工具,該過程可確保使用者輕鬆存取您Windows Forms應用程式的完整功能和特性。 這個簡化的部署過程幫助您向觀眾傳達可靠、專業的Windows桌面應用程式。
結語
在這堂課程的結尾,Tim Corey展示了一個完整的、使用文字文件作為資料庫的資料持續系統。 更重要的是,他展示了真實世界中的錯誤是如何出現的,模式是如何指導修正的,並且為何理解執行順序比追求完美更重要。
此課程並不是關於華而不實的資料庫——而是關於思考像一名開發者。

