2013-05-16 47 views
1

考慮:從現有的winforms應用程序中分離出視圖層的路徑?

  1. 我們的組織有一個標準的Windows窗體應用程序
  2. 的形式和業務邏輯相互交織 - 即Autonomous View。我們知道自主視圖模式使得編寫單元測試變得困難。我們的目標是採取單一形式,並將表現邏輯與表單本身分離,以便我們擁有一個獨立的域實體/對象,可以更輕鬆地針對它編寫單元測試。
  3. 我們沒有做完整的重寫。我正在尋找一種漸進的方法,可以單獨處理一個屏幕。
  4. 經過一番研究,我認爲Presentation Model模式或MVVM模式最適合這個組織做事情的方式。
  5. 該組織通常偏好較少的間接層次,因此更簡單(即使不太穩健)更好。
  6. 從過去到現在應該是公式化(容易教導任何已經熟悉內部概念的開發人員)。這就是爲什麼他們想要通過其他更新的技術如WPF堅持使用Windows窗體。
  7. 域模型對視圖(表單)一無所知。表單將完全意識到域模型的更改。這使得兩層間接。再多1個就可以了(這就是爲什麼我會允許MVVM)。

我發現的大多數MVVM示例都演示了它如何與WPF配合使用,而不是使用普通的舊窗體。

兩個問題:

考慮到這一切,有什麼事我說了,你想我不是一個很好的路徑上,或者我在錯誤的軌道上?我期待向管理層提出一些建議。

最後,你知道一個很好的在線代碼示例,可以幫助我充實原型嗎?

+0

winforms不支持MVVM。 MVVM實際上是專門爲WPF創建的,主要基於Martin Fowler的[Presentation Model](http://martinfowler.com/eaaDev/PresentationModel.html) –

+0

如果您期望winform支持MVVM,您將需要一個基於winforms的框架支持諸如(Real)DataBinding,DataTemplates,DataTriggers等等。沒有這些概念,MVVM就不可能存在。沒有這樣的框架,所以你必須自己創建它。這是一個毫無意義的巨大努力。這就像爲QBasic創建一個Windows UI框架。 –

+0

感謝HighCore。我確定有一個混合(或替代方法),它可以做類似我所問的事情(即使WPF是MVVM的自然伴侶)。我對那些也曾經想過穿越這座橋的人有興趣。 – Mario

回答

0

我不想成爲回答我自己的問題的人之一,但另外的研究和實驗已經闡明瞭一些事情。

理想的解決方案是,領域對象的提取本身與組織中使用的設計實踐非常相似。從本質上講,它可能是在其所有UI榮耀中提取出一種視覺形式,而是一種更抽象的形式(「VM」或視圖模型),它體現了表單(組合,按鈕等)上使用的概念,而沒有使用實際的用戶控件。然後,VM將被綁定到實際找到控件的視圖。

不幸的是,這是一項艱鉅的努力,其中抽象必須足夠強大,以與他們所映射的控件類似的方式行事。因爲我們的組織有幾十個和幾十個自定義控件,那不是簡短的訂單。

以一個簡單的內部組合框爲例。組合表示具有一組受限選項的輸入。我們的數據模型是一個內存數據集。組合綁定到一個特定的表格,並且當用戶填寫表格並因此提供標準時,他的允許選擇被進一步過濾。該組合向用戶(DisplayMember)顯示一個值,並將另一個值保存到DB(ValueMember)。它可能比這更多一點;然而,組合的「場」抽象必須考慮其中的一些概念,以便它最終能夠正確地映射到視圖。此外,我們的表單訂閱了來自其控件的大量事件。這些必須以某種方式映射。所以在我看來,很多形式(視圖)功能必須在虛擬機中有對應的功能。虛擬機因此在某種程度上變成了它所代表的物理形式的陰影。

我原本以爲有可能提取表單及其組成控件的非常一般的抽象,然後將該抽象(與原始表單非常相似)映射到視圖。儘管這可能是可行的,但我現在認爲這是不切實際的,並且本身可能會帶來一系列新問題。

所以,雖然我想避免測試對實際表單實例運行,但我認爲這可能會更好,試圖添加一個抽象層。建立這種抽象將類似於努力使用另一範例來重寫我們的屏幕,從而不保留屏幕的原始形狀。也就是說,即使我們可能會一次重寫一個表格,從而允許逐步過渡,最終版本也不會像原先所希望的那樣重複使用最初的結構。

1

也許你可以做的最好的事情就是看看你的代碼庫,着眼於single responsibility principle。自治視圖(以及培育它的winform)如此難以測試的主要原因之一,是因爲開發人員傾向於在事件處理程序中將所有內容組合在一起。

在SO - https://stackoverflow.com/questions/16599778/asp-net-mvc3-linq-make-multiple-related-rows-fields-in-a-1-to-many-relationshi上提出這個問題,它是關於MVC3的,但它是一團糟 - 一種負責配置gridview,配置響應以及檢索數據以填充gridview的方法。很難甚至不知道從哪裏開始回答問題,更不用說寫出任何合理的(閱讀:簡潔的&快速執行)測試,以確保解決方案的工作。

如果您可以仔細檢查您的代碼,並仔細將所有業務邏輯和/或集成點封裝到服務/組件/接口(和實現)中,最好在外部單獨的程序集中。

一旦將所有邏輯分解爲單獨的組件,每個組件都集中在它自己的concern上,那麼您可以編寫測試以確保它們執行它們的任務,而無需測試應用程序的任何其他部分,這些將是您的服務。你想拍攝每種服務類型作爲實現支持的接口。

將所有這些不同的項目和程序集編寫並測試後,使用inversion of controldependency injection的一種形式)將它們重新引入到您的應用程序中。這進一步將您的UI從應用程序要執行的各種業務邏輯中分離出來。這裏的夢想是,當你準備重寫UI時,你可以到達一個地方,你可以重用已經被編寫和測試過的業務邏輯組件。我在想,winform類將有一個構造函數接受很多參數(上面討論的各種服務的組合)。 DI框架將負責向winform類提供服務。之後,理想情況下,您的winforms事件處理程序將相對較小,只需使用從各種表單字段收集的參數值調用服務方法即可。

這是一篇關於使用winforms:Using Castle.Windsor with Windows Forms ApplicationsCastle Windsor(依賴注入框架)的文章。有許多不同的DI框架,我使用Castle Windsor,因爲它是我第一次學習的,他們都做基本相同的事情,所以,你需要做的就是找到一個你感覺舒服的人。

這是基於Web應用程序的separation of concerns tutorial,但應該對如何從現有的「廚房水槽」應用程序中識別&重構服務提供指導。

這個答案正在變成一本書,而且都非常抽象。最重要的是,你需要將應用程序看作一組樂高積木,並將它們結合起來以產生功能(每個模塊都是一個問題),並且使用者界面只不過是將積木固定在一起的粘合劑(這種比喻並不完美) 。

真的,它比藝術更具藝術性,但你可以訓練你的思維以這種方式來看問題,一旦你做了,一般來說,編程變得更容易。曲線有點陡峭,但是,保持它,你會到達那裏。

+0

感謝您花時間提供您的見解。我確信我們的團隊(包括我自己)可以制定一種將業務邏輯提取到其自己的層的方法。我問的主要問題是,如果從某種已經被嘗試和打磨的方法中得到了可靠的原則,就不要再重新發明。無論如何,你的觀點都很好。謝謝。 – Mario

0

我認爲你最好的選擇是將ElementHosts放在你現有的winforms應用程序中,並將WPF內容放入它們中。然後你可以使用WPF和MVVM,並逐漸將你的winforms應用程序升級到WPF。

即使您在winforms中使用某種輔助框架,您也會遇到一些限制,從而導致骯髒,笨拙的解決方案污染您嘗試實現的清潔。

例如,winforms中沒有任何東西可以提供與WPF ItemsControlDataTemplates相同的功能。看看ListBoxthis example與WPF中的一些DataTemplates。無論你在Winforms中如何使用ListBox都能達到這樣的效果,無論你整合了多少第三方框架。

底線:將ElementHosts與WPF內容放在每個表單中,您可以逐步清理所有的winforms混亂成乾淨的,MVVM,可測試的,獨立於分辨率的,簡單美觀的WPF UI。我堅持認爲(並且沒有人能證明我錯了),這是從winform中獲得任何體面的唯一方法。

+1

我很欣賞你的周到反饋,但這家商店不想轉移到WPF。這家商店有幾個企業級應用程序,都建立在相同的內部框架之上。許多開發人員都希望轉向更新的技術,但這不是我們的要求。 – Mario

相關問題