利用午休時間繼續把過去寫的一些代碼翻出來說一說,文章可能寫的比較簡略,但是我會努力把核心意思表達清楚,具體代碼可直接訪問 Github 獲取。
Github 地址:https://github.com/iccb1013/Sheng.Winform.Controls.Controller
這些代碼是針對 WinForm 寫的,但稍加改動即可應用於 WPF 開發中。
提到控制器,我們可能會首先想到流行的 MVC 開發中的控制器 Controller。對於 MVC 開發來說,我們把工程結構划分為 模型、視圖、控制器。這是比較宏觀的工程角度的划分,那么對於一些小范圍的,更具體的編碼問題,這樣的模式是否能夠借鑒呢?答案是肯定的。
在我們的客戶端應用程序開發中,可能會涉及大量的控件操作的代碼,如 TreeView,DataGridView,ListBox 等等,這些控件雖然都提供了基本的數據操作接口,但是這些接口的功能都非常的基礎和簡單,考慮如下操作:
- 在控件中使指定的數據處於選中狀態;
- 在控件中刪除符合條件的數據;
- 向控件中的指定位置添加數據,並判斷數據的類型是否符合預期;
- 在控件中查找符合條件的數據;
- 獲取控件中選中的數據,直接返回強類型結果;
- 移動指定的數據到另一個數據項目之前/之后;
- 展開樹控件中符合條件的樹節點;
這些操作有一個重要的共同點,都是針對“數據”進行操作,但是基本的的控件接口,沒有這么多功能,既有的接口也多是以 object 作為參數來操作的,如果要實現這些功能,很多時候程序員需要寫一些“業務代碼”來完成,在業務代碼中迭代數據源,寫條件判斷,做類型轉換,最后調用控件的基本操作接口。
通常代碼看起來如下圖這樣:
那么這些共通的功能,是否能夠抽象出來呢?於是我們可以考慮繼承這些控件,來添加我們想要的功能:
我們把這些共通的操作,實現在繼承的控件中,然后在項目中使用自己實現的控件,這不失為一個辦法,但是通過繼承來實現這樣的功能,有很大的缺陷:
- 必須在項目中所有使用控件的地方,使用繼承而來的控件,對於全新開發的項目尚可考慮,但是對於中后期的項目,再去修改這些控件代價與風險過高;
- 有些項目本身使用了第三方控件,那么你針對原生控件的繼承的實現就無法使用,必須針對第三方控件再做一次繼承和實現;
- 有時我們會需要某些特定的操作,只在某些情況下使用,如果全部寫在繼承的控件中,代碼可能會冗余和過大,如果在繼承的基礎上再繼承一次,結構過於繁雜;
這里要引出一句話:對象的復合優於對象的繼承。
我們使用復合不同的對象(控件和控制器)的方法,來解決這個問題:
我們可以為不同的控件,實現它們對應的“控制器”,然后在控制器中,實現我們的這些方法,這樣做可以最大程度的獲得靈活性與可控性,我們直接使用原生(或第三方控件)來開發項目,然后在代碼中,為控件初始化一個控制器,接下來使用控制器來操作控件,對於上文提到的除了共通的操作外,還需要某些特定的操作的情況,可以實現為不同的控制器進行操作。
看一個控制器實現的代碼示例,這是一個支持通過類型(Type)來呈現和操作數據的 DataGirdView 的控制器:
使用構造函數接收一個原生的 DataGridView 控件實例來包裝它,及時是第三方控件,只要它是繼承自 DataGridView 的,就可以直接使用。
接下來就可以直接使用控制器中的諸多方法,來操作控件,實現我們上文中提到的諸多功能。
代碼的具體實現其實並不復雜,並且代碼寫於很多年前,有些細節的實現現在看來也並非最佳,只為拋磚引玉,輕拍。
具體的代碼實現可以訪問我的 Github 獲取,包括:
- DataGridViewController
- TabControlController
- TreeViewController
- ListBoxController
你可以直接使用這些代碼,也可以參考這些代碼和本文所提出的思路,實現更多的控件控制器。
Q:279060597 @南京
http://sheng.city/post/github-winform-wpf-sheng-winform-controls-controller