簡體   English   中英

模型視圖演示者,如何在視圖之間傳遞實體?

[英]Model view presenter, how to pass entities between view?

編輯:接受了克里斯·霍姆斯(Chris Holmes)的回應,但如果有人想出更好的方法,請隨時准備重構。 謝謝!

用MVP做一些winforms是將實體傳遞到另一個視圖的最佳方法。

假設我有一個CustomerSearchView/Presenter ,在doubleClick上我想顯示CustomerEditView/Presenter 我不希望我的視圖了解模型,因此無法創建在參數中使用ICustomer的ctor。

我的反應是

CustomerSearchView創建一個新的CustomerEditView ,它創建它自己的演示者。 然后,我的CustomerSearchView將執行以下操作:

var customerEditView = new CustomerEditView();
customerEditView.Presenter.Customer = this.Presenter.SelectedCustomer;

其他可能的方法是使用CustomerDTO類,並使CustomerEditView接受其中的一個CustomerDTO ,但是我認為這很簡單。

對基本問題很抱歉,但是我能找到的所有示例都沒有達到那個程度,這是一個棕地項目,到目前為止使用的方法讓我頭疼...

我不知道您是如何顯示自己的觀點的,因此在此處為您提供具體建議有些困難。 這是我之前做過此類事情的方式:

我們所做的是讓CustomerSearchViewPresenter觸發類似OpenCustomer(customerId)的事件。 (這是假設您的搜索視圖僅包含少量客戶數據,而customerId將是其中的一個。如果您的搜索視圖具有列出的整個Customer對象,則可以調用OpenCustomer(customer)。但是我不會構建一個搜索視圖,並允許其填充整個對象...我們在數據方面保持搜索視圖的輕量化。)

該應用程序中的其他地方是一個事件處理程序,該事件處理程序偵聽OpenCustomer()事件並執行創建帶有Presenter的新CustomerEditView的任務(而我將遵照我的IoC容器為我做這些事情,所以我不這樣做)不必在任何地方使用“ new”關鍵字)。 創建視圖后,我們可以將ID(或客戶對象)傳遞給新的CustomerEditView,然后顯示它。

負責列出OpenCustomer()事件並執行CustomerEditView創建的此類通常是我們應用程序中的某種Controller類。

為了進一步簡化這種情況,我采用了另一種方法:在應用程序或模塊啟動時,我同時創建了CustomerSearchView(&presenter)和CustomerEditView(&presenter)。 當CustomerSearchView需要打開Customer進行編輯時,CustomerEditView成為OpenCustomer事件的響應者,並將數據加載到自身中,並且知道如何在應該做的任何容器中顯示自己。

因此,有多種方法可以做到這一點。

怎么樣:

//In CustomerSearchPresenter
var presenter = new CustomerEditPresenter();
var customerEditView = new CustomerEditView(presenter);
presenter.SetCustomer(customer);

//In CustomerEditPresenter
public void SetCustomer(customer)
{
    View.Name = customer.Name;
    View.Id = customer.Id;
    ...
}

考慮到您的客戶搜索視圖應僅委托給其演示者,您需要執行一個操作。

  1. 我將看一下MS Prism 4及其漂亮的導航界面。 另請參閱Silverlight和WCF導航。 它們做得很好,可以處理諸如提示用戶從“臟”表單中進行確認(取消)的操作。

  2. 我還將查看WCF中的PageFunction()文檔,以了解如何從另一個“調用”頁面並獲取信息。

運作方式如下(javascript,抱歉):

用戶在客戶列表上雙擊客戶:

CustomerList.onDblClick(customerId){

  app.fireEvent('customerEditRequest', id)

}

...

app.onCustomerEditRequest(id){
  this.mainRegion.requestNavigate('customers/edit', id);
}

如果導航到編輯視圖成功...

CustomerEditView.onNavigatedTo(context){
  this.model.load(context.parameters.id));
}

CustomerEditView.onSaveButtonClick(){
  this.model.save();
  app.fireEvent('customerEdited', id);
}

...

app.onCustomerEdited(id){
  app.mainRegion.requestNavigate('customerlist', id);
}

您可以通過幾種不同的方式來做到這一點:

  1. 從客戶列表中向編輯表單發送一個回調函數。 編輯表單將調用它,調用它時您可以執行所需的操作。

  2. 讓您聽到並回應的“ customerEdited”事件產生編輯表單(無應用程序范圍內的總線)

  3. 如圖所示,使用應用程序范圍的事件總線來集中管理事件。

我曾經讓我的觀點與他們的演示者進行交流,但是已經脫離了這一點。 它與模式的原始定義不符(這本身不是導致實現這些好處的一個主要因素)。 理想情況下,視圖應保持愚蠢狀態,並盡可能減少依賴項。 視圖應通過代理/事件/某種“即發即棄”機制與演示者(任何“觀察者”)進行通信。 實際上,我已經在MVP中引入了一個控制器,專門用於攔截View事件,並(很少)重新觸發到Presenter以與Presenter進行通信,或者與系統或Presenter特定的事件總線進行通信-使我能夠在不觸摸視圖的情況下更改用戶操作警報機制。 但是必須注意事件總線; 很快,您就會開始在其中引發所有事件,應用在處理事件時會變得閑談/陷入困境,而事件並不是.Net中最快的事情。 同步是一個額外的問題,尤其是當您的應用需要與用戶進行更多“對話式”交互時。

應該記住,盡管Presenter是特定於視圖/流程的,但是視圖(和視圖模型)可以重用; 使View與Presenter處於包含/委派關系中會強烈耦合View /限制其復用。 可以通過一些DI來減少這種情況,但是我發現DI容器在大多數情況下都沒有必要的復雜性(因為我仍然必須知道如何創建對象,並且在創建/測試它后,您多久將另一個語義相似的對象更改為一個對象?)。 具體的依賴性無處不在,除了另一層/增加了更多的模糊性/使事情更難以調試/跟蹤。 但是最近處於“簡單”狀態,並且大多數情況下,我更喜歡在大多數應用程序上執行Factory /對象創建/ ORM映射,因為通常使用“一對一”的btw db表/實體,並且需要添加通用的第三方ORM工具的復雜性,即通過通用的上下文/需要為不同的應用程序提供服務,即使您了解它們的工作原理(並非重點),也必須使事情變得比他們需要的更難。

而且,對於View來說,在MVP中觀察模型還是很可行的(就像在MVC中一樣),因此我不能很快排除這一點。 我不想自己做,但不會“破壞”模式。 實際上,大約十年前,我開發了與MVP類似的東西,因為我不喜歡MVC組件之間的“循環”。 我更喜歡將所有這些模式(包括MVC)都聲明為View和Model之間更清晰的分離,以及希望盡可能使View保持沉默(觀察Model意味着View需要更多的智能來處理Model更改)。 我最終要做的是像MVVM和策略模式,在其中我使用模型的“子結構”傳遞給View,充當“變更通知者”。 這樣可以使所有視圖都具有特定目的且靈活/可重復使用(強壯的組合)。

要獲得任何MVP代碼中的自然流程,有一些關鍵的見解:

  1. 是由主持人驅動視圖,而不是相反。
  2. 由於1.視圖不需要知道演示者的存在。 較少的依賴關系通常意味着更容易維護。

在C#中,當將演示者與視圖分離時,我發現事件是一項重要資產。 先前的答案中有更多詳細信息: WinForms中的Model-View-Presenter

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM