如何在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
仍然不知道Presenter
和Model
任何内容。 它只是触发事件,从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