模型视图演示者,如何在视图之间传递实体?

时间:2009-02-10 20:28:39

标签: c# winforms mvp

编辑:已接受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,但我认为这很简单。

对不起基本的问题,但我发现的所有例子都没有达到这一点,这是一个棕色的项目,到目前为止使用的方法让我很头疼......

5 个答案:

答案 0 :(得分:4)

我不知道你是如何展示你的观点的,所以在这里给你提供具体的建议有点困难。这就是我之前做过这种事情的方式:

我们所做的是让CustomerSearchViewPresenter触发像OpenCustomer(customerId)这样的事件。 (假设您的搜索视图只有一些客户数据,而customerId就是其中之一。如果您的搜索视图中列出了整个Customer对象,那么您可以调用OpenCustomer(客户)。但我不会构建一个搜索视图并允许其填充整个对象...我们将搜索视图保持为轻量级数据。)

应用程序中的其他地方是一个事件处理程序,它监听OpenCustomer()事件并执行创建一个新的CustomerEditView w / Presenter的任务(我将按照我的IoC容器为我做这些事情,所以我不必在任何地方使用“new”关键字。创建视图后,我们可以将id(或客户对象)传递给新的CustomerEditView,然后显示它。

这个负责列出OpenCustomer()事件并执行CustomerEditView创建的类通常是我们应用程序中的某种Controller类。

为了进一步简化这种情况,我采用了另一种方式:当应用程序或模块启动时,我创建了CustomerSearchView(& presenter)和CustomerEditView(& presenter)。当CustomerSearchView需要打开Customer进行编辑时,CustomerEditView将成为OpenCustomer事件的响应者并将数据加载到自身中,并知道如何在应该执行的任何容器中显示自己。

所以有多种方法可以做到这一点。

答案 1 :(得分:1)

怎么样:

//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;
    ...
}

在认为您的客户搜索视图应该委托给其演示者时,您需要执行操作。

答案 2 :(得分:0)

在任何MVP代码中获得自然流程有几个重要的见解:

  1. 这是主持人推动视野,而不是反过来。
  2. 由于1.视图无需了解演示者的存在。较少的依赖性通常意味着更容易维护。
  3. 在C#中,我发现在将演示者与视图分离时,事件是一项重要的资产。上一个答案中的更多详细信息:Model-View-Presenter in WinForms

答案 3 :(得分:0)

  1. 我会看一下MS Prism 4,以及他们漂亮的导航界面。另请参阅Silverlight和WCF导航。他们做得很好,并处理诸如提示用户从“脏”表单进行确认的事情,并取消。

  2. 我也会查看WCF中的PageFunction()文档,了解如何从另一个页面“调用”页面并获取信息。

  3. 以下是它的工作原理(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. 使用应用程序范围的事件总线集中管理事件,如图所示。

答案 4 :(得分:0)

我曾经让我的观点与他们的主持人沟通,但已经离开了。它不符合模式的原始定义(本身并不是偏离一个促成这些好处的因素的原因)。理想情况下,视图应该保持愚蠢,尽可能少依赖。视图应通过委托/事件/某些“即发即忘”机制与Presenter(任何“观察者”)进行通信。事实上,我已经在MVP中引入了一个控制器来专门拦截View事件,并重新激活到演示者(很少)到与Presenter交流,或者与系统或Presenter特定的事件总线通信 - 使我能够更改用户操作警报机制w / out触摸视图。不过要小心一下活动巴士;很快你就开始把所有事件都抛在那里,app在处理事件时变得很健谈,事件并不是.Net中最快的事情。 Sunchronization是一个额外的问题,特别是如果您的应用需要与您的用户进行更“对话”的互动。

应该记住,尽管Presenter是特定于视图/特定于流程的,但可以重用视图(和视图模型);将视图置于与Presenter的包含/委托关系中会强烈关联View或限制其重用。这可以通过一些DI来减少,但我发现在大多数情况下DI容器是不必要的复杂性(因为我必须知道如何创建对象以及在创建/测试它之后多久更换一个对象以用于另一个语义相似的对象?)。具体的依赖性无处可去,除了另一层/增加了更多的默默无闻/使得调试/跟踪更加困难。最近一直在“简单”踢,并且大多数人更喜欢在大多数应用程序上使用Factory / object创建/ ORM映射,因为有一个“1对1”btw db表/实体,并且需要添加通用上下文/需要为不同的应用程序提供服务的通用第三方ORM工具的复杂性必须使事情变得比他们需要的更难,即使你理解它们是如何工作的(不是重点)。

此外,View在MVP中观察模型仍然是可行的(如在MVC中),所以我不会那么快就把它排除在外。我不喜欢自己这样做,但它并没有“打破”这种模式。事实上,我在大约十年前开发了类似于MVP的东西,因为我不喜欢MVC组件的“循环循环”(查看了解模型);我更倾向于使用所有这些模式(包括MVC)声明的清晰分离btw视图和模型,以及希望尽可能保持View愚蠢(观察模型woujld意味着View需要更多智能来处理模型更改)。我最终做的是类似MVVM和策略模式,我使用模型的“子结构”传递给View,作为“更改通知器”。这使得一切视图都是针对特定目的和灵活/可重用的(艰难的组合)。