6

好的,伙计们,例如,我有这个表格,我之前告诉过你,DockPanel 中只有一个 DockContent

从那时起,我所做的一个编辑是当用户单击左窗格中的某个项目时,每个项目中出现的单词。我轻松地为左窗格创建了一个三元组。

它具有项目演示者、项目视图、项目模型。这是每个东西的接口:

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 回答 4

2

为了在演示者之间进行协调,当用户选择不同的项目时,您可以让您的MainForm班级实施IProjectsViewObserver并在右侧停靠窗格上设置文本。例如:

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

如果你想测试这种行为,你可以创建一个单独的类:

class DockPaneProjectUpdater : IProjectsViewObserver

尽管在这种情况下这是不必要的,因为代码非常简单。

您可以使用匿名方法调查更简单的方法来执行此操作,但我不知道足够的 C# 来帮助您。

我做两个三合会而不是一个对吗?

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

如何协调两个三合会?

创建一个窗口级演示器,它连接子演示器并可以协调三元组之间的行为。您可以让 window-presenter 成为 aIProjectsViewObserver并根据DockContent. 或者,如果您真的想对行为进行模块化/单元测试,您可以创建一个单独的演示者类(通常是匿名类)用于三合会之间的通信。

任何建议/建议/提议/建议/提示任何许多其他您认为对我有用的东西都将不胜感激!

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

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

于 2012-05-11T20:17:07.727 回答
1

如果你想在你的三元组之间实现完全精简和抽象的交互方式,你可以使用Mediator 模式。创建“消息”类/结构,一个演示者将订阅它,另一个将发送它。

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

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

于 2012-05-26T15:51:43.010 回答
1

听从加勒特的建议。由相互了解并可以采取相应行动的主演示者创建子演示者。最简单的方法是在两个窗格的子演示者中创建一个属性。

你来自 Java 世界吗?:) C# 有自己的观察者模式实现:事件。请看一下,这样您就不再需要额外的类似 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;
    }
}

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

于 2012-05-13T17:49:10.717 回答
0

我创建了一个名为 EventHub 的静态类,它可以注册“监听器”并发布新事件。我自己是 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" );
于 2016-09-26T08:00:47.910 回答