MVP和UserControls以及调用方式

15

我正在尝试理解与用户控件相关的MVP(模型-视图-控制器)内容,具体使用的是.NET WinForms(或类似的框架)和监督控制器模式(至少我认为是这样的 :)。

用户控件本身是MVP应用程序的一部分(它是视图,有关联的Presenter等)。Presenter始终首先启动,然后启动Model和View。View构建其UI,其中部分内容是NEW UC,即视图。

现在(表单)Presenter需要知道UC Presenter的情况,但我认为它对视图的组成方式一无所知。例如,表单Presenter不知道UC是表单Control集合的一部分,也不应该知道。

此外,设计经验不应改变;换句话说,View(表单)的开发人员应该能够从工具箱中选择User Control并将其放置在表单上。

那么,进入我的问题。首先,我上面的假设是否正确?有些误导?混乱了吗?你在想什么?

第二,将表单View调用UC View,表单Presenter调用UC Presenter,并有某种机制告诉UC View它的Presenter是否正确(足够吗?)。这打破了我的“先Presenter”规则,但我不确定还有其他方法。

欢迎提出任何其他想法,建议和评论。

——nwahmaet

3个回答

14
一个Presenter应该被视为演示层中的“自主状态”。这意味着它负责确保视图对模型状态的呈现同步。之所以提出这个问题,是因为MVP模式的“模式”经常在教条的视角中丢失。看起来这是Martin Fowler决定尝试澄清MVP模式的术语的原因之一。
我喜欢的MVP风格是被动视图,所以我的答案是基于这个的。
我经常使用被动视图模式实现组合用户控件和表单。基本上有3种不同的配置:
1.整个层次结构中所有用户控件共用一个Presenter。使用接口展开视图。 2.复合树中每个用户控件都有一个Presenter。每个父Presenter负责实例化和初始化其子Presenter。用户控件在设计时创建,并且可以在没有Presenter的情况下(没有呈现行为)运行。 3.复合树中每个用户控件都有一个Presenter。所有Presenter通过更高级别的控制器类松耦合。控制器类负责构建Presenter,将它们连接起来并协调它们的事件。
虽然对我来说这是最后的解决方案(因为它的复杂性),但我认为最后一个选项是您要寻找的解决方案。

如果能提供一个这样的内容就太好了。我在如何在更复杂的WinForms中实现MVP模式方面遇到了很大的困难,很难找到详细的信息... - Tomas Pajonk
我在Web表单中的用户控件上遇到了类似的问题。页面和每个用户控件都有自己独立且不相关的Presenter。每个Presenter加载相同的基础数据实体是完全可能的。虽然这种模式具有出色的代码重用性,但显然会比必要的情况下更频繁地访问数据库。 - Rebecca
你说得对,像HTML这样的断开视图技术使状态管理更加困难。在WebForms中,很难保持事务粗粒度。我知道在ASP.Net MVC中,只有当所有部分视图组合使用一个模型绑定器时,组合才能起作用。被动视图确实最适合有状态技术,如WinForms或WPF。 - Michael Meadows
请问您能回答一下这个问题吗?http://stackoverflow.com/questions/8851933/event-bubbling-and-mvp-asp-net - LCJ

4
我在应用程序中遇到了这个问题已经好几个月了。最近的结论是,在许多情况下,将MVP模式应用于窗口和用户控件层级可能是不可能的,否则会“破坏”该模式。我的想法是,用户控件是视图实现的一部分,而Presenter不应该知道视图实现内部发生了什么。这意味着窗口级别的Presenter也不应该知道用户控件的Presenter,因此它们之间不应该有任何通信,包括由前者实例化后者。可以认为用户控件的Presenter是窗口视图实现的一部分,因此窗口视图可以实例化用户控件的Presenter。但它无法注入Presenter所需的模型类,因为视图不应该知道它们。我认为我得出的结论是,所有用户控件都是特定于视图实现的,因此应完全包含在较大模式的视图隔间中。因此,它们不能拥有自己的Presenter,至少不是与控件实现捆绑在一起的。相反,它们应该通过视图接口上公共的 pass-through 接口间接地受到父窗口的Presenter的操作。简而言之,用户控件不是通过其自己的接口向Presenter公开的,而是通过其父视图实现的公共 pass-through 接口向Presenter公开的。将此称为“部分视图接口”。然后,您的Presenter可以包含可重用子Presenter类的实例,该子Presenter类仅使用此部分视图接口和相关模型的部分。这将使您避免每次需要使用控件时都要重新编写Presenter代码以从模型中进行翻译,并且它还防止了窗口视图需要了解模型以便传递信息到控件的Presenter。实际上,这样做会进一步将用户控件作为一个模块与数据模型分离。如果您把用户控件整体视为视图实现的一个元素,那么这就说得通了。作为可重复使用单位,它是视图功能的一部分,其中没有任何部分应与您的数据模型绑定。

2
我同意所有的UC都是视图实现特定的,但也觉得它们需要自己的Presenter或Model,具体取决于UC的目的。导航面板可能有Presenter逻辑而不是Model;而邮政编码查找则需要一个Model。 - nwahmaet
1
我理解您的观点。我的感觉是,尽可能避免将自定义控件与模型绑定在一起。像这样与应用程序架构紧密耦合的控件我称之为“臃肿”控件。它们就像迷你子窗口,非常难以处理,同时保持设计的简洁/清晰。 - Chris Ammerman

0

你的问题比较普遍,有多种方案可以应用。

在这种情况下,我猜你应该看一下观察者模式。

你需要一个接口,所有使用该视图的内容都要实现它。然后,在应用程序初始化时,它会向这些接口的集合注册自己。任何需要更新该视图的命令都会遍历该集合,通知每个视图应该被更新。

与典型的示例不同,这些视图将是用户控件。你可以灵活地使任何 UI 元素实现该接口,因此除了用户控件之外,还可以使用对话框、完整表单等。

最后,请记住,用户控件不是视图,而是视图的实现。无论采用什么方案,你都可以定义视图的深度,并让用户控件实现该接口。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接