通過 Tim Corey 的比賽查看器解釋 WinForms 數據綁定
介紹
在 C# App Start to Finish 系列的第22課中,Tim Corey 開始著手於 Tournament Viewer 表單,主要專注於 WinForms 的資料綁定上。 Tim 說明這節課並不是關於將資料儲存到數據庫或文本文件—那將在稍後的課程中。 相反地,本影片的整個目的是連接UI、填充控制項,並了解如何使用資料綁定在模型與WinForms控制項之間移動資料。
Tim 清楚地指出,WinForms 的資料綁定可能會顯得笨拙、令人困惑,有時甚至令人沮喪。 因此,這節課成為了一次深入實際的資料綁定行為的演練,探討其如何運作、如何被破壞及如何修復。 通過跟隨 Tim 的除錯過程,我們對 WinForms 的資料綁定機制有了現實而有價值的理解。
Tournament Viewer 表單概述
Tim 首先描述了 Tournament Viewer 表單應該執行的功能。 表單顯示:
-
競賽名稱
-
包含競賽回合的下拉清單
-
顯示所選回合比賽的列表框
- 所選比賽的隊伍名稱及比分
Tim 強調所有的資訊必須保持同步。 當回合變更時,賽程必須更新。 當賽程變更時,隊伍名稱及比分必須更新。 這個要求驅動了整個關於資料綁定的討論。 與相同的資料來源綁定的控制項,也被稱為資料綁定控制項,自動保持同步。 BindingNavigator 控制項通過保持記錄列表中項目的指標為當前來處理數據的綁定。 CurrencyManager 類管理列表控制項與數據源對象之間的綁定集合,允許位置跟踪和變更通知。 每個綁定的控制項,如 TextBox 或 Label,透過這些機制連結到數據源,以確保自動同步。
將 Tournament 對象傳入表單
Tim 說明 Tournament Viewer 表單不應該決定要載入哪個比賽。 這項責任屬於儀錶板。 因此,Tournament Viewer 表單必須通過它的構造函數接收一個 TournamentModel。
他示範如何將傳遞進來的比賽對象存儲在表單級別的私有字段中,讓它可以被表單中的每個方法訪問。 這個比賽對象成為所有資料綁定操作的單一真理來源。 在簡單的資料綁定中,可以將控制項與單一數據元素綁定,例如來自單一資料表的值,使您可以顯示或編輯個別的數據點。 BindingSource 可以用於簡單和複合綁定情境中。
載入表單數據的方法
Tim 介紹了一個名為 LoadFormData 的私有方法。 這個方法從比賽模型中提取數據並將其推送到UI控制項中。
例如:
- 比賽名稱標籤直接從 tournament.TournamentName 獲得其值。 這涉及將控制項的屬性,如文本框控制項的文本屬性,設置為來源數據中的值。
Tim 強調這是資料綁定的最簡單形式—手動分配值—這是一個處理列表和集合之前的好起點。 簡單綁定將控制項的單個屬性連接到數據來源中的單個值,通常一次顯示一條記錄。
連接儀錶板按鈕
Tim 逐步講解如何修改儀錶板,使當用戶選擇了一個比賽並點擊"載入比賽"時,Tournament Viewer 表單開啟。
在這裡,Tim 將選擇的下拉項目轉換為 TournamentModel 並傳遞給查看器表單。 他透過運行應用程式並看到比賽名稱正確顯示來證實連接正常運作。
這證明了在進入列表綁定之前,基本對象傳遞和UI更新的運作良好。
從資料來源載入回合到下拉清單
現在,Tim 進入列表綁定,從比賽回合開始。
他說明回合最好用整數列表來表示,而不是字符串。 Tim 明確表示這個選擇使生活更輕鬆,因為:
-
整數能夠乾淨地綁定到下拉清單
-
不需字符串解析即可檢索整數
- 選定值可以直接轉換回整數
ComboBox 控制項可以綁定到給定的表或列表上,讓您能有效地顯示和選擇數據。 在綁定 ComboBox 控制項時,您可以使用 DisplayMember 屬性來指定顯示給使用者的欄位,而 ValueMember 屬性用於決定作為底層值的欄位。 類似地,您可以將 DataGridView 控制項綁定到包含於資料表中的信息。
Tim 繞過比賽的回合,提取唯一的回合編號,並將它們存儲在列表中。
使用資料繫結連接回合下拉菜單
Tim 介紹了第一個重要的 WinForms 綁定規則:
在重設之前,始終將 DataSource 設置為 null。
他清除此下拉菜單的數據來源,然後將回合列表分配給它。 當將控件綁定到數據源時,若資料源實現 INotifyCollectionChanged 等接口,控件在數據變更時將自動刷新其UI。 這確保了數據和其視覺表示之間的實時同步。 此外,UI控制項或底層數據源的變更會自動更新綁定的另一端,根據配置(單向或雙向)。 由於整數能夠自然轉換為字符串,他解釋說此處不需要DisplayMember。
Tim 接著演示了一個常見的錯誤—遺忘呼叫載入方法—並展示了錯過一個方法呼叫如何導致空的下拉菜單。
SelectedIndexChanged事件和動態更新
Tim 說明WinForms高度依賴事件,尤其是SelectedIndexChanged。
他將回合下拉菜單的SelectedIndexChanged事件連接到一個方法,該方法載入所選回合的比賽。 在WinForms資料綁定中,事件處理程序接收 object sender 參數,該參數識別觸發事件的控制項。 您可以處理以下事件,例如 Format 和 Parse,以自定義資料格式化和驗證; Binding 類的Format 和Parse 事件允許在資料綁定過程中進行特殊的資料格式化和驗證。 其他控制項也可以通過類似的事件處理進行綁定和同步。
Tim 更喜歡將邏輯提取到私有輔助方法中,而不是將程式碼直接放入事件處理程序中。 他解釋這樣可以保持程式碼的可重用性和整潔性。
根據選定的回合載入比賽
Tim 通過將下拉選擇項轉換回整數來獲取所選的回合。
他再次遍歷比賽的回合,但這次過濾出比賽回合等於所選回合的賽程。 這些比賽賽程被放入已選賽程列表中,成為賽程列表框的數據來源。
這引入了綁定複雜對象列表的挑戰。
創建顯示屬性進行綁定
Tim 說明,賽程模型沒有適合用於UI顯示的自然字符串表示。
Tim 並沒有將邏輯強加到UI上,而是向模型中添加了一個只讀的 DisplayName 屬性。 此屬性構建一個字符串,如:
隊伍 A vs. 隊伍 B
如果缺少隊伍(例如輪空週或後續回合),Tim 返回:
賽程尚未確定
複雜綁定控制項,如 DataGridView,支持複雜的綁定情境,其中資料表或其他結構的多個數據元素可以被顯示和編輯。 複雜的資料綁定允許您將多個數據元素綁定到一個控制項上,如從底層記錄來源綁定多個列或行。 ADO.NET 提供了許多適合綁定的數據結構,包括 DataTable、DataView 以及其他結構,Windows Forms 支持綁定到多個數據源。 Binding class 管理資料來源字段與控制属性之間的邏輯链接,並且接口如 IBindingList、IEditableObject 和 INotifyPropertyChanged 提供排序、變更通知和還原支持。 您可以在資料視圖上設置默認過濾器來控制數據顯示的方式,資料綁定上下文及 CurrencyManager 最終決定資料綁定控制項的同步。 Windows Form 的 BindingContext 屬性管理表單的 CurrencyManager 對象,每個 資料源有一個單一的 CurrencyManager 對象,將所有綁定到相同資料源的控制項同步。 可以在 Windows Forms 中創建自定義控制項,通過實現必要的數據綁定接口,這些控制項可以像標準資料綁定控制項一樣運作。
這是一個由 Tim 強調的WinForms資料綁定關鍵原則:
模型應該決定它是如何顯示的,而不是 UI。
調試綁定錯誤
Tim 遇到了多個錯誤:
-
第二回合未正確顯示
-
賽程未刷新
- 事件意外觸發
Tim 沒有掩蓋這些問題,而是逐步講解每個調試步驟。他解釋當列表被替換時,儘管新列表包含有效數據,但綁定會斷裂。
這導致了一個重要的 WinForms 課程。
以下程式碼演示如何處理 Binding 類的 Format 和 Parse 事件,以在數據綁定過程中提供特殊的資料格式化及驗證。 Format 事件和 Parse 事件可以用於自定義資料在UI和數據源之間的轉換和驗證方式。
BindingSource 與 BindingList 在 Windows Forms 資料綁定中的比較
Tim 使用 BindingSource 進行實驗,將其放在 UI 控制項與數據之間。 他解釋這曾經是推薦的方法,但承認它增加了複雜性和困惑。 BindingSource 組件作為數據源與 Windows Forms 控制項之間的代理,並適用於多種類型的數據結構,如 DataTables、DataViews、BindingLists 和數組。
然後,他介紹了 BindingList ,解釋其在列表更改時自動更新綁定的控制項。 如果資料源实现适當的接口,例如 INotifyCollectionChanged,則 Windows Forms 中的資料綁定支持在底層數據更改時自動更新控制項。
然而,Tim 發現了一個至關重要的規則:
您必須不要將 BindingList 替換為新的一個。
相反,您必須:
-
清除現有的 BindingList
- 將項目重新添加進去
替換列表會破壞綁定連結。
通過清空列表修復壞掉的綁定
Tim 確認綁定問題的根本原因:
-
分配新的 BindingList() 會斷開 UI 聯接
- 清空和重新添加項目能保持綁定
他更新了回合和賽程以使用此模式。 一旦保持一致地應用,UI最終更新正確。
手動載入初始選擇
Tim 說明 WinForms 不會在載入項目時自動觸發 SelectedIndexChanged。
為了解決這個問題,他手動:
-
載入回合1的賽程後載入回合
- 程式化選擇第一個賽程
這確保了 UI 在不需要用戶互動的情況下正確初始化。
最終結果和課程總結
在課程結束時,Tim 確認:
-
回合更新正確
-
賽程更新正確
-
隊伍名稱和比分正確加載
- 輪空週和未來回合顯示有意義的文本
他強調這節課不是關於完美,而是了解 WinForms 資料綁定的真正行為,包括它的限制。
Tim 結束時說明計分和篩選(如"僅未玩")將在下一節課中處理,當有實際狀態變更可供使用時。
結束思考
第22課不僅是一個實用的 WinForms 資料綁定大師課,因為不是一切都順利運作,而是因為 Tim Corey 即時地演練了每次失敗、修復和設計決定。
透過跟隨 Tim 的影片,開發者能夠現實地理解:
-
為什麼 WinForms 資料綁定感覺脆弱
-
BindingList 如何運作
-
為什麼清理列表很重要
- UI 如何應與模型互動
如果您曾經在WinForms資料綁定中掙扎過,這節課和 Tim 的解釋最終讓"為什麼"豁然開朗。
