MVP模式下Winform之间的通信

Communication between winforms in mvp pattern

我在开发应用程序时遇到了一个大问题。 这是一个基于C#的Winforms基础应用程序,实现了Model-View-Presenter模式,但是我对此方法并不陌生。 我到处搜索,但是找不到我的问题的答案。

我需要知道如何使用此模式在Winform之间进行通信,以及演示者如何在不将演示者耦合到表单的情况下显示它们。 我已经看到了使用Factory模式的方法,但不了解如何实现它。

任何帮助或指出正确方向的人,将不胜感激。


在MVP中,winforms不应相互通信。
表格A知道其演示者A,
表格B认识其主持人B

通常,您将通过Prensenter A使用表单A修改模型。演示者B将听取模型更改,并相应地刷新表单B。

如果需要更多协调,可以考虑使用应用程序控制器

参见http://dotnetslackers.com/articles/designpatterns/The-Presenter-in-MVP-Implementations.aspx


断言

演示者负责视图和模型之间的协调(如果遵循被动视图实现)。

可能看起来像:

实例化Presenter并将其注入Presenter的View:

1
2
IPresenter presenter;
public View() { presenter = new Presenter(this) }

演示者实例化一个或多个视图并将其自身插入到视图中:

1
2
3
4
5
6
IView1 view1;
public Presenter() { view1 = new View1(this) }

IView1 view1;
IView2 view2;
public Presenter() { view1 = new View1(this); view2 = new View2(this); }

在您的情况下,协调多个视图的Presenter可能看起来像这样(伪):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Presenter : IPresenter
{
  IView1 view1;
  IView2 view2;
  public Presenter()
  {
    view1 = new View1(this);
    view2 = new View2(this);
  }

  private WireViewEvents()
  {
    view1.OnButtonClick += HandleButtonClickFromView1;
  }

  public void HandleButtonClickFromView1()
  {
    view2.SetSomeData();
    view2.Show();
}

在此示例中,演示者处理由View1引发的事件,在View2中设置数据,并显示View2

请记住,无论您采用哪种实施方式,MVP的目标都是:

  • 关注点分离(UI与域逻辑分离)。
  • 提高可测试性。

请注意,这只是演示者如何协调多个视图的基本示例。如果要从演示者中提取View创建内容,则可以将创建内容移到Presenter调用以创建视图并订阅其事件的另一个容器中。


我只是显示一个虚拟代码,其中2个视图试图通过Presenter使用接口相互通信。这是一个简单的示例,请让mw知道是否有故障。老实说,我没有测试过此代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
namespace WindowsFormsApplication1
{
    internal class View1 : IView1
    {
        public View1()
        {
            new Presenter(this);
        }


        public string Username { get; set; }
        public event EventHandler ShowDetails;
    }
}

namespace WindowsFormsApplication1
{
    internal class View2 : IView2
    {
        public View2()
        {
            new Presenter(this);
        }

        public string Position { get; set; }
    }
}

namespace WindowsFormsApplication1
{
    public class Presenter
    {
        private readonly IView1 _view1;
        private readonly IView2 _view2;

        public Presenter(IView1 view1)
        {
            _view1 = view1;
            _view1.ShowDetails += ShowDetails;
        }

        private void ShowDetails(object sender, EventArgs e)
        {
            _view2.Position = _view1.Username =="My Name" ?"Arhchitect" :"Project Manager";
        }

        public Presenter(IView2 view2)
        {
            _view2 = view2;
        }

    }

}

public interface IView1
{
    string Username { get; set; }

    event EventHandler ShowDetails;
}

public interface IView2
{
    string Position { get; set; }
}

但是在这个例子之后有一些注意事项。要开始使用您的应用程序,请尝试使用1 View界面或2来决定要使用的第一个天气。如果您可以使用一个界面,则可能会遇到甚至是轻松的情况。


我认为前面提到的有关模型生成事件的要点是正确的,以使演示者知道更改是正确的。我确实有几点意见,希望对您有所帮助。

首先,View实现可能不是单一形式。有时,通过单独的(可能是模态的)形式维护模型的一部分是有意义的,该形式实际上就像是View中的复杂控件。在这种情况下,表单之间的交互将是直接的。演示者不应该关心View实现的完成方式。

其次,当看起来需要交互的表单显然不是同一视图的一部分时(例如,查找表单),我将使用"应用程序控制器"模式来重新命令。在这种情况下,当窗体A需要执行功能(例如"查找产品"或"编辑详细信息")时,它将在自己的Presenter上调用方法来执行此操作。然后,Presenter会在Application Controller上调用一个单独的方法(所有Presenters都引用该方法,这是一个单例),然后Application Controller打开具有自己的Presenter的所要求的表单。在WinForms中,所有这些都可以通过模式形式完成,在这种情况下,结果将通过调用链发送回去。或者,将需要在应用程序控制器和演示者之间进行一些事件引发,即,演示者在应用程序控制器上引发有关其已完成操作的事件,从而通知其他代表该事件的演示者。

有关MVP中的Application Controller模式的更多信息,请参见我的博客文章Using the MVP Pattern。