编辑:已接受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
,但我认为这很简单。
对不起基本的问题,但我发现的所有例子都没有达到这一点,这是一个棕色的项目,到目前为止使用的方法让我很头疼......
答案 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代码中获得自然流程有几个重要的见解:
在C#中,我发现在将演示者与视图分离时,事件是一项重要的资产。上一个答案中的更多详细信息:Model-View-Presenter in WinForms
答案 3 :(得分:0)
我会看一下MS Prism 4,以及他们漂亮的导航界面。另请参阅Silverlight和WCF导航。他们做得很好,并处理诸如提示用户从“脏”表单进行确认的事情,并取消。
我也会查看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);
}
有几种不同的方法可以做到:
从客户列表中向编辑表单发送回调函数。编辑表单将调用它,并在调用它时执行您想要的操作。
将“customerEdited”事件的编辑表单加注,您收听并做出反应(没有应用程序范围的总线)
使用应用程序范围的事件总线集中管理事件,如图所示。
答案 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,作为“更改通知器”。这使得一切视图都是针对特定目的和灵活/可重用的(艰难的组合)。