在WinForms中的模型 – 视图 – 演示者

我正在尝试使用WinForms首次实现MVP方法。

我想了解每一层的function。

在我的程序中,我有一个GUIbutton,点击时打开一个openfiledialog窗口。

因此,使用MVP,GUI处理button单击事件,然后调用presenter.openfile();

在presenter.openfile()中,是否应该将该文件的开放委托给模型层,或者由于没有要处理的数据或逻辑,是否应该简单地处理请求并打开openfiledialog窗口?

更新:我决定提供一个赏金,因为我觉得我需要进一步的帮助,最好是针对我下面的具体要点,以便我有背景。

好吧,在阅读MVP之后,我决定实施被动观点。 实际上,我将在Winform上有一堆控件,由Presenter处理,然后委托给Model(s)。 我的具体观点如下:

  1. 当winform加载时,它必须获得一个树形视图。 我认为视图应该调用一个方法,如:presenter.gettree(),这反过来将委托给模型,它将获取树视图的数据,创build并configuration它,返回到主持人,这反过来会传递到视图,然后将其简单地分配给一个面板?

  2. 这将是相同的任何数据控件的Winform,因为我也有一个datagridview?

  3. 我的应用程序,有相同的程序集的许多模型类。 它还支持插件体系结构,需要在启动时加载插件。 该视图是否会简单地调用一个演示者方法,然后调用一个方法来加载插件并在视图中显示信息? 然后哪个层将控制插件引用。 视图是否会引用他们或主持人?

  4. 我是否认为视图应该处理关于表示的每一件事情,从treeview节点的颜色,到datagrid的大小等?

我认为他们是我主要关心的问题,如果我理解这些stream程应该如何,我想我会没事的。

这是我对MVP和你的具体问题的谦逊。

首先 ,用户可以与之交互的任何东西,或只是被显示出来,都是一个视图 。 这种观点的法律,行为和特点是通过一个界面来描述的。 该接口可以使用WinForms UI,控制台UI,Web UI甚至根本没有UI(通常在testing演示者的时候)来实现 – 具体的实现只要遵守其视图接口的规则就没有关系。

其次 ,一个观点总是由主持人控制。 这样的主持人的法律,行为和特点也由界面来描述。 只要遵循其视图界面的规律,该界面对具体视图的实现就没有兴趣了。

第三 ,由于主持人控制自己的观点,为了最大限度地减less依赖关系,所以对于主持人来说,观点一无所知。 主持人和观点之间有一个同意的合同,这是视图界面所陈述的。

的含义是:

  • 演示者没有视图可以调用的任何方法,但是视图具有演示者可以订阅的事件。
  • 主持人知道它的观点。 我更喜欢用具体的演示者的构造函数注入完成这个任务。
  • 这个观点不知道主持人在控制什么。 它将永远不会被提供任何主持人。

对于你的问题,上面可能看起来像这样在一些简化的代码:

interface IConfigurationView { event EventHandler SelectConfigurationFile; void SetConfigurationFile(string fullPath); void Show(); } class ConfigurationView : IConfigurationView { Form form; Button selectConfigurationFileButton; Label fullPathLabel; public event EventHandler SelectConfigurationFile; public ConfigurationView() { // UI initialization. this.selectConfigurationFileButton.Click += delegate { var Handler = this.SelectConfigurationFile; if (Handler != null) { Handler(this, EventArgs.Empty); } }; } public void SetConfigurationFile(string fullPath) { this.fullPathLabel.Text = fullPath; } public void Show() { this.form.ShowDialog(); } } interface IConfigurationPresenter { void ShowView(); } class ConfigurationPresenter : IConfigurationPresenter { Configuration configuration = new Configuration(); IConfigurationView view; public ConfigurationPresenter(IConfigurationView view) { this.view = view; this.view.SelectConfigurationFile += delegate { // The ISelectFilePresenter and ISelectFileView behaviors // are implicit here, but in a WinForms case, a call to // OpenFileDialog wouldn't be too far fetched... var selectFilePresenter = Gimme.The<ISelectFilePresenter>(); selectFilePresenter.ShowView(); this.configuration.FullPath = selectFilePresenter.FullPath; this.view.SetConfigurationFile(this.configuration.FullPath); }; } public void ShowView() { this.view.SetConfigurationFile(this.configuration.FullPath); this.view.Show(); } } 

除了上面的内容外,我通常还有一个基础的IView界面,在这里我存储了Show()以及任何所有者视图或视图标题,这些视图通常都能从我们的视图中受益。

对你的问题:

1. 当winform加载时,必须获得一个treeview。 我认为视图应该调用一个方法,如:presenter.gettree(),这反过来将委托给模型,它将获取树视图的数据,创build并configuration它,返回到主持人,这反过来会传递到视图,然后将其简单地分配给一个面板?

IConfigurationPresenter.ShowView()调用IConfigurationView.SetTreeData(...) ,调用IConfigurationView.SetTreeData(...)之前,

2. 这对于Winform上的任何数据控件都是一样的,因为我也有一个datagridview?

是的,我会为此调用IConfigurationView.SetTableData(...) 。 这是视图格式的数据给它。 主持人简单地遵从视图的合约,它需要表格数据。

3. 我的应用程序,有相同的程序集的许多模型类。 它还支持插件体系结构,需要在启动时加载插件。 该视图是否会简单地调用一个演示者方法,然后调用一个方法来加载插件并在视图中显示信息? 然后哪个层将控制插件引用。 视图是否会引用他们或主持人?

如果插件是视图相关的,那么视图应该知道它们,而不是演示者。 如果他们都是关于数据和模型的话,那么这个观点就不应该和他们有任何关系。

4. 我正确地认为视图应该处理关于表示的每一件事情,从treeview节点颜色到datagrid大小等等?

是。 把它看作提供XML的主持人,描述数据和获取数据并将CSS样式表应用到其中的视图。 具体而言,演示者可能会调用IRoadMapView.SetRoadCondition(RoadCondition.Slippery) ,然后视图以红色呈现道路。

点击节点的数据呢?

5. 如果当我点击treenodes时,是否应该通过特定节点传递给演示者,然后由演示者计算出需要的数据,然后在将模型提交给视图之前询问模型的数据。

如果可能的话,我会一次性传递在一个视图中显示树的所有数据。 但是如果一些数据太大而不能从一开始就传递,或者如果它的性质是dynamic的,并且需要来自模型的“最新快照”(通过主持人),那么我会在event LoadNodeDetailsEventHandler LoadNodeDetails )以便演示者可以订阅它,从模型中获取LoadNodeDetailsEventArgs.Node (可能通过它的某种types的ID)节点的细节,以便当事件处理程序委托返回时,视图可以更新其显示的节点细节。 请注意,如果提取数据可能太慢,以至于不能提供良好的用户体验,则可能需要asynchronous模式。

包含视图中所有逻辑的主持人应该像@JochemKempe 所说的那样响应被点击的button。 实际上,button点击事件处理程序调用presenter.OpenFile() 。 主持人然后能够确定应该做什么。

如果它决定用户必须select一个文件,它将callback到视图 (通过视图界面),并让包含所有UI技巧的视图显示OpenFileDialog 。 这是一个非常重要的区别,因为演示者不应该被允许执行与使用中的UI技术相关的操作。

然后选定的文件将被返回给继续其逻辑的演示者。 这可能涉及任何模型或服务应该处理文件。

使用MVP模式的主要原因是将UI技术从视图逻辑中分离出来。 因此,演示者在视图保持与UI逻辑分离的同时编排所有逻辑。 这使得演示者完全可以unit testing的副作用非常好。

更新:因为演示者是在一个特定视图中find的逻辑的实施例,所以视图 – 演示者关系是IMO一对一关系。 而且对于所有实际的目的,一个视图实例(比如一个Form)与一个演示者实例交互,一个演示者实例只与一个视图实例交互。

也就是说,在使用WinForms实现MVP时,演示者总是通过代表视图UIfunction的界面与视图交互。 对于实现此接口的视图没有限制,因此不同的“小部件”可以实现相同的视图接口并重用演示者类。

主持人应该在请求结束时按照你的build议显示openfiledialog窗口。 由于模型中不需要数据,因此演示者可以并且应该处理请求。

假设您需要数据在您的模型中创build一些实体。 您可以将stream槽传递给访问层,在该层中您可以从stream中创build实体,但是我build议您在演示者中处理文件的parsing,并在模型中为每个实体使用构造函数或Create方法。