MVP三合会之间的沟通

时间:2012-05-11 17:13:21

标签: c# .net winforms design-patterns mvp

好的,伙计们,比如我在Only one DockContent in DockPanel

之前告诉你这个表格

自那时起我做的一个编辑就是当用户点击左窗格中的某个项目时每个项目中的文字。我轻松地为左窗格创建了一个三元组。

它有项目主持人,项目视图,项目模型。这是每个东西的接口:

interface IProjectsModel
{
    void AttachPresenter(IProjectsModelObserver observer);
    System.Collections.Generic.List<Project> projects { get; }
    Project selectedProject { get; set; }
}

public interface IProjectsViewObserver
{
    void UserChangedSelectedProject(Project project);
}
public interface IProjectsModelObserver
{
    void SelectedProjectChanged(Project project);
}

public interface IProjectsView : IView
{
    List<Project> projects { set; }
    Project project { set; }

    void AttachPresenter(IProjectsViewObserver presenter);
}

所以目前我正在考虑为右窗格创建一个全新的另一个MVP三元组。 但这不是主要问题。我跑的主要问题是如何在上面告诉你的MVP三元组之间进行沟通?

我在网上看过一些文章,告诉我们在这种情况下有必要为项目引入一些模型协调员吗?

所以我的问题是:

  1. 我是否正确地做了两个三元组只有一个?
  2. 如何在彼此之间协调两个三元组?
  3. 任何建议/建议/提议/建议/提示任意多 你认为对我有用的其他东西将非常感激!
  4. 非常感谢,伙计们!感谢您的关注和时间!

4 个答案:

答案 0 :(得分:2)

要在演示者之间进行协调,您可以拥有MainForm类实现IProjectsViewObserver,并在用户选择其他项目时在右侧停靠窗格中设置文本。例如:

class MainForm : IProjectsViewObserver
{
    void UserChangedSelectedProject(Project project)
    {
          rightDockPane.setText(project.getText());
    }
}

如果要测试此行为,可以创建一个单独的类:

class DockPaneProjectUpdater : IProjectsViewObserver

虽然在这种情况下这是不必要的,因为代码很简单。

您可以使用anonymous methods调查更简单的方法,但我不知道足够的C#来帮助您。

  

我是否正确地做了两个黑社会而不只是一个?

是的,因为停靠栏和窗格是单独的组件,他们可能需要单独的MVP三元组。您可以通过尝试使代码可重用和可测试来决定MVP三元组的粒度(小)。

  

如何在彼此之间协调两个三元组?

创建一个窗口级演示器,用于连接子演示者并可以协调三元组之间的行为。您可以将窗口展示者设为IProjectsViewObserver并对DockContent采取行动。或者,如果您真的想模块化/单元测试行为,您可以创建一个单独的演示者类(通常是一个匿名类)来进行三元组间通信。

  

任何建议/建议/提议/建议/提示许多其他许多   你认为对我有用的东西将非常感激!

阅读有关MVP和presenter-first的维基百科和在线文章。 MVP的最大好处是可测试性和行为(演示者)模块化,因此请确保您通过unit testing(通常使用模拟/ DI框架)利用它们,并在重用代码时将行为重构为MVP三元组。

需要一些时间来弄清楚如何有效地应用MVP模式,所以请耐心等待!

答案 1 :(得分:1)

按照加勒特的建议。由masterpresenter创建彼此了解并且可以相应操作的子呈现器。最简单的方法是在两个窗格的子提交者中创建一个属性。

你是来自Java世界吗? :) C#有自己的观察者模式实现:events。请看一下,这样您就不再需要额外的类似Java的接口了。

更新:当我开始写作时,我改变了主意。在我看来,演示者之间进行通信的最佳方式是使用共享模型。

class SelectedProjectChangedEventArgs : EventArgs
{
    public Project SelectedProject {get;set;}
}

class Project
{

}

interface IReadOnlyModel
{
    Project SelectedProject {get;} 
    event EventHandler<SelectedProjectChangedEventArgs> SelectedProjectChanged;
}

interface IWritableModel
{
    Project SelectedProject {get;set;} 
    IList<Project> Projects {get;}
}

class Model : IReadOnlyModel, IWritableModel
{
    public Project SelectedProject {get;set;} 
    public event EventHandler<SelectedProjectChangedEventArgs> SelectedProjectChanged;
    public IList<Project> Projects {get;set;}
}

class ProjectsListPresenter
{
    readonly IWritableModel _model;

    public ProjectsListPresenter(IWritableModel model)
    {
        _model = model;
    }

    public void ChangeSelectedProject(Project project)
    {
        _model.SelectedProject = project;
    }
}

class ProjectDetailsPresenter
{
    readonly IReadOnlyModel _model;

    public ProjectDetailsPresenter(IReadOnlyModel model)
    {
        _model = model;
        _model.SelectedProjectChanged += ModelSelectedProjectChanged;
    }

    void ModelSelectedProjectChanged(object sender, SelectedProjectChangedEventArgs e)
    {
        //update right pane
    }
}


class WholeFormPresenter
{
    public ProjectDetailsPresenter DetailsPresenter {get;private set;}
    public ProjectsListPresenter ListPresenter {get;private set;}

    public WholeFormPresenter(Model model)
    {
        DetailsPresenter = new ProjectDetailsPresenter(model);
        ListPresenter = new ProjectsListPresenter(model);
    }
}

class WholeForm
{
    ListBox _projectsListControl;
    Panel _detailsPanel;
    public WholeForm()
    {
        var presenter = new WholeFormPresenter(new Model());
        _projectsListControl.Presenter = presenter.ListPresenter;
        _detailsPanel.Presenter = presenter.DetailsPresenter;
    }
}

我知道类/接口名称并不完美,但我希望这个想法很明确。

答案 2 :(得分:1)

如果您想在三合会之间实现完全瘦弱和抽象的互动方式,可以使用Mediator pattern。创建“消息”类/结构,一个演示者将订阅它,另一个将发送它。

这种方法非常类似于对事件的订阅,但提供了更多的抽象,因为双方的主持人甚至不知道他们的消息的接收者是否存在。由于您在一个进程的上下文中工作,因此您可以在消息中传递任何您想要的内容,甚至是回调代理。 可以在MVVM Light framework中找到介体模式实现的一个很好的例子。它在那里被称为Messenger。看看tests

就个人而言,我在需要时使用mediator在没有共同父级或创建者的对话窗口之间发送信息。在那种情况下,它有助于简化事情。

答案 3 :(得分:0)

我创建了一个名为EventHub的静态类,它可以注册&#34;听众&#34;并发布新活动。我自己用C#做了一点新手,所以我确信有办法让这个课程变得更好:

public enum EventType
{
    // Your event types
}

public static class EventHub
{
    static Dictionary<EventType, List<Delegate>> _eventHandlers;

    // Use this to fire events with input
    public static void Publish( EventType eventType, object data )
    {
        // Fire event handler if found
        if( _eventHandlers.ContainsKey( eventType ) )
        {
            _invokeHandlers( _eventHandlers[ eventType ], data );
        }
    }

    static void _invokeHandlers(List<Delegate> list, object data)
    {
        if( !(list != null && list.Count > 0) )
            return;

        foreach( var handler in list )
            handler.DynamicInvoke( data );
    }

    // Use this to register new "listeners"
    public static void Register( EventType eventType, Delegate handler )
    {
        // Init dictionary
        if( _eventHandlers == null )
            _eventHandlers = new Dictionary<EventType, List<Delegate>>();

        // Add handler
        if( _eventHandlers.ContainsKey( eventType ) )
            _eventHandlers[ eventType ].Add( handler );
        else
            _eventHandlers.Add( eventType, new List<Delegate> { handler });
    }

    // Use this to remove "listeners"
    public static void Dismiss( EventType eventType, Delegate handler )
    {
        // Nothing to remove
        if( _eventHandlers == null || _eventHandlers.Count == 0 )
            return;

        // Remove handler
        if( _eventHandlers.ContainsKey( eventType ) && _eventHandlers[ eventType ].Count > 0 )
            _eventHandlers[ eventType ].Remove( handler );

        // Remove Key if no handlers left
        if( _eventHandlers[ eventType ].Count == 0 )
            _eventHandlers.Remove( eventType );
    }
}

用法:

void MyHandler(object data) { /*...*/ }
EventHub.Register( EventType.MyType, MyHandler );
//...
EventHub.Publish( EventType.MyType, "I am data, I can be anything" );