c# - 如何在 MVP 被动 View 中显示复杂数据

标签 c# winforms design-patterns mvp

我研究 MVP 模式已有一段时间,并设法创建了一些简单的 MVP 兼容应用程序。

我现在正尝试将该模式应用到一个更复杂的应用程序中,但我对这样做的最佳方式存疑。

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

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 是通过构造函数注入(inject)在我的演示者中引用的:

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 正在处理它,检查输入是否有错误并根据我的数据模型构建它。

我的下一步是在 View 中显示处理后的数据。

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

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

此外,我是否正确处理了整个 MVP 问题,还是我遗漏了什么?

最佳答案

在您的View 中使用复杂类型 属性没有任何问题。假设您有一些 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,因此您的 Model 可能看起来像这样

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);
     }
}

关于您的问题

I'm striving to keep my View as passive and "dumb" as possible, assuming it knows nothing of the Presenter (it doesn't subscribe to its events, the Presenter sends data to the View by calling IView methods instead), let alone of the Model.

您的 View 仍然对 PresenterModel 一无所知。它只是触发事件,从 Presenter 获取数据并绑定(bind)其控件。并且您具有可测试性(请注意此单元测试是伪代码,因为我不知道您如何检索数据、您在按钮单击事件中需要什么输入等...)。

[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.");
}

关于c# - 如何在 MVP 被动 View 中显示复杂数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25770413/

相关文章:

java - 让 setter 返回 "this"是不好的做法吗?

c# - 如何将 IObservable<IObservable<T>> 转换为 IObservable<IEnumerable<T>>?

c# - 验证 asp.net web 应用程序中的输入后,将焦点从代码隐藏到文本框

c# - 单实例 .NET Core 应用程序(或使 crontab 仅运行我的应用程序的 1 个实例)

c# - 奇怪的 RichTextBox 行为

design-patterns - 策略设计模式与状态设计模式

design-patterns - 访客模式与双重调度之间的区别

C# MVC 5 - 为日期创建一个 SelectList 不起作用

c# - App.config 中的 Winforms 连接字符串

c# - 从 C# 调用 onclick 方法