简体   繁体   English

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

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

Edit : Accepted Chris Holmes response, but always ready to refactor if someone come up with a better way! 编辑:接受了克里斯·霍姆斯(Chris Holmes)的回应,但如果有人想出更好的方法,请随时准备重构。 Thanks! 谢谢!

Doing some winforms with MVP what is the best way to pass an entity to another view. 用MVP做一些winforms是将实体传递到另一个视图的最佳方法。

Let say I have a CustomerSearchView/Presenter , on doubleClick I want to show the CustomerEditView/Presenter . 假设我有一个CustomerSearchView/Presenter ,在doubleClick上我想显示CustomerEditView/Presenter I don't want my view to know about the model, so I can't create a ctor that take an ICustomer in parameters. 我不希望我的视图了解模型,因此无法创建在参数中使用ICustomer的ctor。

my reflex would be, 我的反应是

CustomerSearchView create a new CustomerEditView , which create it's own presenter. CustomerSearchView创建一个新的CustomerEditView ,它创建它自己的演示者。 Then my CustomerSearchView would do something like : 然后,我的CustomerSearchView将执行以下操作:

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

Other possible approach would be a CustomerDTO class, and make a CustomerEditView that accept one of those CustomerDTO , but I think it's a lot of work something simple. 其他可能的方法是使用CustomerDTO类,并使CustomerEditView接受其中的一个CustomerDTO ,但是我认为这很简单。

Sorry for basic question but all example I can find never reach that point, and it's a brownfield project, and the approach used so far is giving me headache... 对基本问题很抱歉,但是我能找到的所有示例都没有达到那个程度,这是一个棕地项目,到目前为止使用的方法让我头疼...

I don't know exactly how you are showing your views, so it's a bit difficult to give you specific advice here. 我不知道您是如何显示自己的观点的,因此在此处为您提供具体建议有些困难。 This is how I've done this sort of thing before: 这是我之前做过此类事情的方式:

What we did was have the CustomerSearchViewPresenter fire an event like OpenCustomer(customerId). 我们所做的是让CustomerSearchViewPresenter触发类似OpenCustomer(customerId)的事件。 (That is assuming that your search view only has a few pieces of Customer data and the customerId would be one of them. If your search view has entire Customer objects listed then you could call OpenCustomer(customer). But I wouldn't build a search view and allow it to populate with entire objects... We keep our search views lightweight in terms of data.) (这是假设您的搜索视图仅包含少量客户数据,而customerId将是其中的一个。如果您的搜索视图具有列出的整个Customer对象,则可以调用OpenCustomer(customer)。但是我不会构建一个搜索视图,并允许其填充整个对象...我们在数据方面保持搜索视图的轻量化。)

Somewhere else in the application is an event handler that listens for the OpenCustomer() event and performs the task of creating a new CustomerEditView w/ Presenter (and I'm going to defer to my IoC container do this stuff for me, so I don't have to use the "new" keyword anywhere). 该应用程序中的其他地方是一个事件处理程序,该事件处理程序侦听OpenCustomer()事件并执行创建带有Presenter的新CustomerEditView的任务(而我将遵照我的IoC容器为我做这些事情,所以我不这样做)不必在任何地方使用“ new”关键字)。 Once the view is created we can pass along the id (or customer object) to the new CustomerEditView and then show it. 创建视图后,我们可以将ID(或客户对象)传递给新的CustomerEditView,然后显示它。

This class that is responsible for listing the OpenCustomer() event and performs the creation of the CustomerEditView is typically some sort of Controller class in our app. 负责列出OpenCustomer()事件并执行CustomerEditView创建的此类通常是我们应用程序中的某种Controller类。

To further simplify this situation, I've done this another way: I create both the CustomerSearchView (& presenter) and CustomerEditView (& presenter) when the application or module starts up. 为了进一步简化这种情况,我采用了另一种方法:在应用程序或模块启动时,我同时创建了CustomerSearchView(&presenter)和CustomerEditView(&presenter)。 When the CustomerSearchView needs to open a Customer for editing, the CustomerEditView becomes the responder to the OpenCustomer event and loads the data into itself, and knows how to show itself in whatever container it is supposed to do. 当CustomerSearchView需要打开Customer进行编辑时,CustomerEditView成为OpenCustomer事件的响应者,并将数据加载到自身中,并且知道如何在应该做的任何容器中显示自己。

So there's multiple ways to do this. 因此,有多种方法可以做到这一点。

How about: 怎么样:

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

In think your customer search view should just delegate to its presenter you need to have an action execute. 考虑到您的客户搜索视图应仅委托给其演示者,您需要执行一个操作。

  1. I would look at MS Prism 4, and their nice Navigation interface. 我将看一下MS Prism 4及其漂亮的导航界面。 Also look at Silverlight and WCF Navigation. 另请参阅Silverlight和WCF导航。 They are well done and handle things like prompting the user for confirmation from "dirty" forms, with cancellation. 它们做得很好,可以处理诸如提示用户从“脏”表单中进行确认(取消)的操作。

  2. I would look at the PageFunction() documentation in WCF as well, for how to "call" a page from another, and get back info. 我还将查看WCF中的PageFunction()文档,以了解如何从另一个“调用”页面并获取信息。

Here's how it works (javascript, sorry): 运作方式如下(javascript,抱歉):

User double-clicks customer on customer list: 用户在客户列表上双击客户:

CustomerList.onDblClick(customerId){

  app.fireEvent('customerEditRequest', id)

}

... ...

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

If navigation to edit view was successful... 如果导航到编辑视图成功...

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);
}

There are a few different ways you could do it: 您可以通过几种不同的方式来做到这一点:

  1. send a callback function to the edit form, from the customer list. 从客户列表中向编辑表单发送一个回调函数。 edit form will call it, and you do what you want when it's called. 编辑表单将调用它,调用它时您可以执行所需的操作。

  2. have the edit form raise on "customerEdited" event that you listen to and react to (no app-wide bus) 让您听到并回应的“ customerEdited”事件产生编辑表单(无应用程序范围内的总线)

  3. use an application-wide Event Bus to manage the events centrally, shown. 如图所示,使用应用程序范围的事件总线来集中管理事件。

I used to have my views communicate with their presenters, but have moved away from that. 我曾经让我的观点与他们的演示者进行交流,但是已经脱离了这一点。 It doesn't conform to the original definition of a pattern (not a reason in itself for deviating just a contributing factor to exact those benefits). 它与模式的原始定义不符(这本身不是导致实现这些好处的一个主要因素)。 Views ideally should be kept as dumb and with as few dependencies as possible. 理想情况下,视图应保持愚蠢状态,并尽可能减少依赖项。 View should communicate w/ Presenter (any "observers") via delegates/events/some "fire-and-forget" mechanism. 视图应通过代理/事件/某种“即发即弃”机制与演示者(任何“观察者”)进行通信。 As a matter of fact, I've introduced a controller into MVP specifically to intercept View events and either re-fire to presenter (rarely) to communite w/ Presenter, or to communicate with a system or Presenter-specific event bus - enabling me to change user action alerting mechanisms w/out touching the view. 实际上,我已经在MVP中引入了一个控制器,专门用于拦截View事件,并(很少)重新触发到Presenter以与Presenter进行通信,或者与系统或Presenter特定的事件总线进行通信-使我能够在不触摸视图的情况下更改用户操作警报机制。 Have to be careful with an event bus though; 但是必须注意事件总线; pretty soon you start throwing all events in there, app gets chatty/bogged down in handling events, and events aren't the fastest things in .Net. 很快,您就会开始在其中引发所有事件,应用在处理事件时会变得闲谈/陷入困境,而事件并不是.Net中最快的事情。 Sunchronization is an added concern, esp if ur app need to have a more "conversational" interaction with your user. 同步是一个额外的问题,尤其是当您的应用需要与用户进行更多“对话式”交互时。

Should bear in mind that although Presenter is usu view/process-specific, views (and view-models) can be reused; 应该记住,尽管Presenter是特定于视图/流程的,但是视图(和视图模型)可以重用; having the View in a containment/delegation relationship with the Presenter strongly couples View/limits its reuse. 使View与Presenter处于包含/委派关系中会强烈耦合View /限制其复用。 This could be reduced by some DI, but I find DI containers to be unnecessary complexity in most cases (since I have to know how to create objects anyway and how often do you change out an object for another semantically similar one after creating/testing it?). 可以通过一些DI来减少这种情况,但是我发现DI容器在大多数情况下都没有必要的复杂性(因为我仍然必须知道如何创建对象,并且在创建/测试它后,您多久将另一个语义相似的对象更改为一个对象?)。 Concrete dependency goes nowhere except another layer/adds more obscurity/makes things more difficult to debug/trace. 具体的依赖性无处不在,除了另一层/增加了更多的模糊性/使事情更难以调试/跟踪。 Been on a "simplicity" kick lately though, and mostly prefer to do my on Factory/object creations/ORM mappings for most apps, since there's usu a "1-to-1" btw db tables/entities and n need for the added complexity of a generic 3rd-party ORM tool that by taht generic context/needing to serve different apps has to make things harder than they need to be, even if u understand how they work (not the point). 但是最近处于“简单”状态,并且大多数情况下,我更喜欢在大多数应用程序上执行Factory /对象创建/ ORM映射,因为通常使用“一对一”的btw db表/实体,并且需要添加通用的第三方ORM工具的复杂性,即通过通用的上下文/需要为不同的应用程序提供服务,即使您了解它们的工作原理(并非重点),也必须使事情变得比他们需要的更难。

Moreover, it's still quite feasible for View to observe Model in MVP (as in MVC), so I wouldn't be so quick to rule this out. 而且,对于View来说,在MVP中观察模型还是很可行的(就像在MVC中一样),因此我不能很快排除这一点。 I don't prefer to do this myself, but it' doesn't "break" the pattern. 我不想自己做,但不会“破坏”模式。 Matter of fact, I developed something similar to MVP about a decade ago because I didnt like the "circular loop" btw the MVC components (View knowing about Model); 实际上,大约十年前,我开发了与MVP类似的东西,因为我不喜欢MVC组件之间的“循环”。 I preferred to have the cleaner separation btw View and Model that all these patterns (including MVC) professed, as well as a desire to keep View as dumb as possible (observing Model woujld mean View would need more intelligence to process Model changes). 我更喜欢将所有这些模式(包括MVC)都声明为View和Model之间更清晰的分离,以及希望尽可能使View保持沉默(观察Model意味着View需要更多的智能来处理Model更改)。 What I ended up doing was something like MVVM and strategy patter, where I used "substructures" of the model to pass in to the View, serving as "change notifiers". 我最终要做的是像MVVM和策略模式,在其中我使用模型的“子结构”传递给View,充当“变更通知者”。 This kept everything view purpose-specific and flexible/reusable (tough combo). 这样可以使所有视图都具有特定目的且灵活/可重复使用(强壮的组合)。

There are a couple of crucial insights to get a natural flow in any MVP code: 要获得任何MVP代码中的自然流程,有一些关键的见解:

  1. It's the presenter that drives the view, not the other way around. 是由主持人驱动视图,而不是相反。
  2. Because of 1. the view need not know about the presenter's existence. 由于1.视图不需要知道演示者的存在。 Less dependencies usually means easier maintenance. 较少的依赖关系通常意味着更容易维护。

In C#, I find events being a great asset when decoupling presenters from views. 在C#中,当将演示者与视图分离时,我发现事件是一项重要资产。 More details in a previous answer: Model-View-Presenter in WinForms 先前的答案中有更多详细信息: WinForms中的Model-View-Presenter

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM