如何在MVP被动视图中显示复杂数据

我一直在寻找MVP模式一段时间,并设法创建一些简单的符合MVP的应用程序。

我现在试图将这种模式应用到更复杂的应用程序中,并且对这样做的最佳方式有些怀疑。

我的应用程序有一个WinForm,有两个按钮用于加载两种不同类型的数据。 我的视图界面如下所示:

interface IView_MainForm
{
    //  Load input
    //
    event EventHandler<InputLoadEventArgs> LoadInput_01;
    event EventHandler<InputLoadEventArgs> LoadInput_02;

    bool Input01_Loaded { get; set; }
    bool Input02_Loaded { get; set; }
}

IView在我的演示者中通过构造器注入被引用:

public Presenter_MainForm(IView_MainForm view)
{
    this.View = view;
    this.View.LoadInput_01 += new EventHandler<InputLoadEventArgs>(OnLoadInput_01);
    this.View.LoadInput_02 += new EventHandler<InputLoadEventArgs>(OnLoadInput_02);
}

到现在为止还挺好。 当用户单击两个按钮中的任何一个来加载数据时,引发LoadInput _ ##事件,Presenter正在处理它,检查输入是否有错误并根据我的数据模型对其进行构造。

我的下一步是将处理后的数据显示回视图中。

我努力让视图尽可能保持被动和“愚蠢”,假设它对Presenter一无所知(它不会订阅它的事件,Presenter通过调用IView方法将数据发送到View),更不用说了的模型。

如果View不知道数据模型是什么样的,我该如何填充一个像TreeView这样的控件?

另外,我是否正确地获得了整个MVP的事情,还是有什么我错过了?


View使用complex type属性没有任何问题。 假设你有一些ComplexType

class ComplexType
{
   public string ParentNode {get;set;}
   public List<string> ChildNodes {get;set;}
   // some other properties
}

我们还假设ComplexType是您的TreeView数据模型。 MVP模式在您的View上具有ComplexType属性是完全正确的。 所以有这样的事情是非常好的

interface IView_MainForm
{
    //  Load input
    //
    event EventHandler<InputLoadEventArgs> LoadInput_01;
    event EventHandler<InputLoadEventArgs> LoadInput_02;

    bool Input01_Loaded { get; set; }
    bool Input02_Loaded { get; set; }

    ComplexType Input01Data {get;set;} // you might actually have some code in get/set setters
    ComplexType Input02Data {get;set;} // you might actually have some code in get/set setters

    public void SetInput01Data(ComplexType input01Data)
    {
       Input01Data = input01Data;
       // some other stuff
    }
}

由于您的Model是针对具有2个输入的View ,因此您的模型可能看起来像这样

public interface IModel
{
   public ComplexType Input01Data {get;set;}
   public ComplexType Input02Data {get;set;}
}

现在在您的Presenter您只需处理View触发的事件,填充Model并在View上设置属性

class Presenter
{
    private IModel _myModel...
    private IRepository _repository;
    public Presenter(IView_MainForm view, IRepository repository)
    {
        _repository = repository;
        this.View = view;
        this.View.LoadInput_01 += new EventHandler<InputLoadEventArgs>(OnLoadInput_01);
        this.View.LoadInput_02 += new EventHandler<InputLoadEventArgs>(OnLoadInput_02);
    }

    public void OnLoadInput_01(object sender, InputLoadEventArgs e)
    {
         // get data based on passed arguments (e.SomeProperty)
         // construct IModel
         myModel = _repository.GetData(e.SomeProperty);
         // pass data to IView_MainForm
         View.SetInput01Data(myModel.Input01Data);
     }
}

关于你的关心

我努力让视图尽可能保持被动和“愚蠢”,假设它对Presenter一无所知(它不会订阅它的事件,Presenter通过调用IView方法将数据发送到View),更不用说了的模型。

您的View仍然不知道PresenterModel任何内容。 它只是触发事件,从Presenter获取数据并绑定其控件。 并且你有testability (请注意这个单元测试是伪代码,因为我不知道你是如何检索数据的,你在按钮点击事件中需要什么输入等)。

[Test]
public void ShouldLoadInput01DataOnButtonClick()
{
   // Arrange
   IModel data = // create dummy data

   Mock<IView_MainForm> clientsViewMock = new  Mock<IView_MainForm>();
   Mock<IRepository> clientsRepositoryMock = new Mock<IRepository>();

   clientsRepositoryMock.Setup(repository => repository.GetData(something)).Returns(data.Input01Data);     
   var presenter = new Presenter(clientsViewMock.Object, clientsRepositoryMock .Object);

   // Act
   clientsViewMock.Raise(view => view.LoadInput01 += null, new InputLoadEventArgs());

   // Assert
   clientsViewMock.Verify(view => view.SetInput01Data(data.Input01Data), "Input01 data expected be set on button click.");
}
链接地址: http://www.djcxy.com/p/30229.html

上一篇: How to display complex data in MVP Passive View

下一篇: How to Form.ShowDialog() using MVP and Passive Views?