【问题标题】:MVP and UserControls and invocationMVP 和 UserControls 和调用
【发布时间】:2009-01-09 20:04:19
【问题描述】:

我在尝试了解一些 MVP 内容时获得了一些乐趣,因为它与用户控件有关。我正在使用.NET WinForms(或类似的东西)和监督控制器模式(嗯,我想我是:)。

用户控件本身是 MVP 应用程序的一部分(它的视图和相关的演示者等)。 Presenter 总是首先启动,它启动模型,然后是视图。 View 构建其 UI,其中一部分将用于 NEW UC,即 View。

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

此外,设计体验不应改变; IOW 视图(表单)的开发人员应该能够从工具箱中选择一个用户控件并将其拖放到表单上。

那么,关于我的问题。首先,我上面的假设是否正确?有点误入歧途?弄乱?你在想什么?

其次,让表单 View 调用 UC View,表单 Presenter 调用 UC Presenter 并有一些机制告诉 UC View 它的 Presenter 是正确的(足够吗?)?这违反了我的“演讲者优先”规则,但我不知道该怎么做。

任何其他想法、建议、cmets 很乐意接受。

--nwahmaet

【问题讨论】:

    标签: winforms design-patterns user-interface mvp


    【解决方案1】:

    演示者应被视为演示层中的“自治状态”。这意味着它负责确保视图对模型状态的表示是同步的。我提出这个的原因是因为 MVP 的“模式”经常迷失在如何事物应该分离的教条观点中。这似乎是 Martin Fowler 决定尝试clarify the terminology around the MVP 模式的原因之一。

    我最喜欢的 MVP 风格是 passive view,所以我的回答就是基于此。

    我经常使用被动视图模式来实现复合用户控件和表单。基本上有 3 种不同的配置:

    1. 层次结构中所有用户控件的一个演示者。使用界面展平视图。
    2. 复合树中的每个用户控件都有一个演示者。每个父 Presenter 负责实例化和初始化其子 Presenter。用户控件是在设计时创建的,并且能够在没有演示者的情况下运行(没有演示行为)
    3. 复合树中的每个用户控件都有一个演示者。所有的演示者都通过更高级别的控制器类松散耦合。控制器类负责构建演示者,将它们连接起来,并协调它们的事件。

    虽然它对我来说是最后的解决方案(因为它的复杂性),但我认为最后一个选择是您正在寻找的解决方案。

    【讨论】:

    • 如果能提供一个就太好了。我很难找到有关如何在更复杂的 winform 中实现 MVP 模式的详细信息...
    • 我在 Web 表单中的用户控件方面也遇到了类似的问题。页面和每个用户控件都有自己独特且不连贯的演示者。每个演示者很可能加载相同的底层数据实体。尽管该模式具有出色的代码重用性,但显然它对数据库的影响超出了它应有的程度。
    • 您说得对,HTML 等断开连接的视图技术使状态管理变得更加困难。无论如何,很难让您的交易在网络表单中保持粗粒度。我知道在 ASP.Net MVC 中,组合仅在所有部分视图组合有一个模型绑定器时才有效。被动视图确实最适合有状态的技术,例如 winforms 或 WPF。
    【解决方案2】:

    在我正在开发的应用程序中,几个月来我一直在解决这个确切的问题。我最近得出的结论是,在许多情况下,在不“破坏”模式的情况下,可能无法在窗口和用户控件级别应用 MVP 模式。

    我的想法是用户控件是视图实现的一部分,演示者不应该知道视图实现内部发生了什么,这意味着扩展的窗口级演示者不应该知道用户控件的演示者,因此它们之间不应该有任何通信,包括前者对后者的实例化。可能有人认为用户控件的演示者是窗口视图实现的一部分,因此窗口视图可以实例化用户控件演示者。但它不能注入演示者需要的模型类,因为视图不应该知道它们。

    我想我得出的结论是,所有用户控件都是特定于视图实现的,因此应该完全包含在更大模式的视图筒仓中。因此,他们没有自己的演示者……至少没有与控制实现本身捆绑在一起。相反,它们应该由父窗口的演示者通过在视图界面上公开的传递字段间接操作。简而言之,用户控件不是通过其自己的接口向演示者公开的,而是通过其父视图实现的通用传递接口。称之为“局部视图界面”。

    然后,您的演示者可以包含一个可重用的子演示者类的实例,该类仅适用于该部分视图界面,​​以及模型的相关部分。这将允许您避免在每次需要使用控件时重新编写演示者代码以从模型进行转换,并且它可以防止窗口视图需要了解模型以便将信息传递给控件的演示者。

    它的有效作用是将用户控件作为一个模块与您的数据模型进一步分离。如果您将用户控件作为一个整体视为视图实现的一个元素,那么这是有道理的。作为一个可重用的单元,它是一个视图功能,它的任何部分都不应该与您的数据模型绑定。

    【讨论】:

    • 我同意所有 UC 都是特定于视图实现的,但也认为他们需要自己的 Presenter 或 Model,这取决于 UC 的用途。 Navigation 面板可能有 Presenter 逻辑而不是 Model;邮政编码当然需要一个模型。
    • 我明白你的意思。我的感觉是,应尽可能避免将自定义控件绑定到您的模型。像这样与你的应用程序架构绑定的控件我称之为“胖”控件。它们就像迷你的子窗口,在保持设计简洁/简单的同时非常难以处理。
    【解决方案3】:

    您的问题很笼统,可以应用多种方案。

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

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

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

    最后记住,用户控件不是视图,而是视图的实现。无论您采用哪种方案,您都可以根据需要定义视图的深度,并让用户控件实现该接口。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-22
      • 1970-01-01
      • 2014-01-19
      • 2014-12-24
      • 2017-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多