我在WinForms中涉足了MVP,還有很多問題需要解決。大多數問題來自於你在VS中的事實,並且能夠使用Forms設計器輕鬆設計表單是很好的。
我試用了一個由廣泛使用的WebForms MVP項目開發的WinForms MVP API,但由於表單使用泛型的文件背後的代碼(例如public class TheForm:UserControl),您將失去設計窗體的能力,因爲設計師知道如何處理泛型。
我結束了與核心接口,IPresenter,IView,IViewModel去。即使我沒有添加任何額外的屬性,我總是爲特定的實現創建了一箇中間接口,主要是因爲稍後當我想要額外添加時,容易進行更改。IPresenter採用類型爲IView的同變種generice類型所以在繼承鏈中,我可以製作特定子視圖類型的演示者。最終創建一個對話框實例化一個演示,並調用顯示完成:
ISomePresenter<ISomeView> somePresenter = new SomeFactory.GetSomePresenter();
somePresenter.Show();
我的觀點持有IViewModel的副本:
public void Show()
{
ISomeView theView = new V();
theView.ViewModel = new SomePresenterViewModel();
.
.
.
}
沒有回到原來的問題... 的SampleView無法瞭解ISampleViewModel,因此無法將ViewModel進行標準數據綁定而無需在其他位置投射。這在我開發所有這些東西的項目中失控,人們在事件處理程序以及BindingSource嚮導中遍佈各處。 MVP的全部內容都丟失了。
因此,現在我已經非常嚴格地處理事件,並將控件設置爲屬性中的公共屬性(以及附帶的ISampleView屬性),以便演示者可以看到它們或者簡單地創建重複事件以重新啓動該活動將由主持人提起我一直在思考整個Databinding難題。真的,做到這一點的唯一方法是沒有設計人員的支持,並完成設計人員在Presenter的代碼中所做的一切。也許可以使用Designer在.designer.cs文件中獲取自動生成的代碼,但將所有代碼剪切到Presenter中。也許這樣做只是爲了獲得語法等,然後打開一些鍋爐板代碼或創建一個基於生成的代碼片段。您仍然需要訪問視圖上的實際控件以指定綁定,因此還需要將屬性添加到返回控件實例的ISampleView。另外,我建議將BindingSource實例放入Presenter中,或者至少讓Presenter擁有實例的其他類。
我喜歡儘可能地使用設計師,但有時您需要休息一下。 正如我所說的CodePlex上的WinForms MVP項目很棒,但所有的表單設計都是在代碼中完成的。在我的場景中,只有DataBinding需要在代碼中完成,而這實際上並不是一個可視化的東西,因此處理起來更容易。
此外,作爲一個附註,用戶NotifyPropertyWeaver(IL編織)支持完整的數據綁定。這很棒,因爲您可以在視圖模型中創建自動屬性,這使得您的代碼變得簡潔並且更具可讀性,而無需在每個屬性上調用NotifyPropertyChanging等。 IL Fitting with Fody在最終構建輸出步驟之前完成所有後期編譯。非常方便。
無論如何,我希望圍繞這個問題的這個大腦轉儲概念對某個人有價值。我花了很長時間把它整理出來,但對我來說它工作得很好。
史蒂夫
編輯2014年4月23日
你知道嗎,.NET數據綁定是流浪漢一個巨大的痛苦。最近在一個項目中,我們剛剛結束了自己的數據綁定代碼的特定控制,因爲它們都很難處理。
重新思考我最初的答覆還有更近的經驗,核心模型應該保持完全獨立。我傾向於創建我稱之爲ViewModel的ViewModel,它與數據庫進行交談,並且是DataBindable並由View查看。數據綁定讓我非常悲傷,尤其是在處理控件事件時,比如DateTimePicker的ValueChanged。在一種情況下,我有一個開始和結束日期選擇器以及一個複選框,以便將結束日期設置爲開始日期後一天以及我需要考慮的其他範圍規則。在根據某些規則更改值時,將數據綁定配置給虛擬機,事件再次觸發並最終取得我所做的最重要的選擇。我最終不得不放置bool值來幫助瞭解事件處理程序是否應該繼續,然後有潛在的競爭條件或不知道事件處理程序(在另一個線程中)是否應該等待。非常迅速得到混亂。因此,我現在的做法是創建一個大型的MODEL,觸及數據庫,並且可以根據捕獲的數據進行驗證規則檢查,但是我會創建一個小而輕的版本,它只保存數據綁定的屬性。與真實模型的分離仍然存在,並且Presenter/Controller響應的任何事件都可以在表單數據驗證/數據持久化時間從VM複製到主模型。如果我對事件做出響應,然後將vm值綁定到一個更輕的虛擬機,我可以創建一個全新的虛擬機實例並重新分配驗證結果,然後將此新的虛擬機實例設置爲.DataSource當我準備好時,視圖上的BindingSource避免了事件處理器的混亂。
主模型可以響應NotifyPropertyChanged事件更新自己的更改或更好的只是讓主持人在適當的時間做到這一點。
順便說一句,似乎Visual Studio 2012和2013現在處理非常酷的設計師的通用控件。
作爲一個方面說明,我一直在iOS開發最近涉足。有一件事讓我印象深刻,就是他們在MVC中作爲過程的一部分被烘焙的方式,與.NET不同的是,它允許我們採用各種方式來實現它。我從中吸取了一些教訓,並將它們應用於.NET,並發現我的大腦並沒有突破這麼多。我特別喜歡的一件事是列表控件的工作方式,它非常類似於Qt(C++框架)MVC控件。具有單體後端對象列表的能力,但視圖只能保持它在可見區域需要的東西比.NET控件的默認行爲好得多。
無論如何,祝你好運與.NET數據綁定。我個人建議任何新來者......不要使用它,只需讓控制器在適當的時候明確地分配所有的值。但是,如果你感到舒服並且能夠理解煩人的細微差別,我希望我所說的某些東西能夠傳達給某個人。
爲什麼在視圖中引用模型將是一個壞主意?我只是向我的演示者添加一個方法,將模型綁定到IView。 –
@WiktorZychla:我在演示者中封裝了視圖和模型。目的是讓演示者以外的任何對象都不應該混淆它的觀點 - 包括模型。否則,在其他對象接管視圖控制的情況下可能發生函數蠕變。 – IAbstract
然後讓您的演示者使用視圖模型,即吸收演示者中的模型並將視圖綁定到演示者,因爲它將是視圖模型。這將是一個推薦的方法。 –