这是我对MVP和你的具体问题的拙见.
First,用户可以与之交互或只是显示的任何东西都是view.这一观点的规律、行为和特点由一个例子来描述.该界面可以使用WinForms UI、控制台UI、web UI甚至完全没有UI(通常在测试演示者时)来实现——只要遵守视图界面的规则,具体的实现就无关紧要.
Second时,视图始终由presenter控制.这类演讲者的法则、行为和特征也由一个interface描述.该接口对具体的视图实现没有兴趣,只要它遵守其视图接口的规则.
Third,因为演示者控制其视图,为了最小化依赖关系,让视图完全了解其演示者实际上没有任何好处.演示者和视图之间有一个约定的合同,这由视图界面声明.
Third的含义是:
- 演示者没有视图可以调用的任何方法,但是视图有演示者可以订阅的事件.
- 演讲者知道自己的观点.我更喜欢通过在混凝土演示器上注入构造函数来实现这一点.
- 视图不知道是什么演示者在控制它;它永远不会提供给任何演讲者.
对于您的问题,在稍微简化的代码中,上面的代码可能如下所示:
interface IConfigurationView
{
event EventHandler SelectConfigurationFile;
void SetConfigurationFile(string fullPath);
void Show();
}
class ConfigurationView : IConfigurationView
{
Form form;
Button selectConfigurationFileButton;
Label fullPathLabel;
public event EventHandler SelectConfigurationFile;
public ConfigurationView()
{
// UI initialization.
this.selectConfigurationFileButton.Click += delegate
{
var Handler = this.SelectConfigurationFile;
if (Handler != null)
{
Handler(this, EventArgs.Empty);
}
};
}
public void SetConfigurationFile(string fullPath)
{
this.fullPathLabel.Text = fullPath;
}
public void Show()
{
this.form.ShowDialog();
}
}
interface IConfigurationPresenter
{
void ShowView();
}
class ConfigurationPresenter : IConfigurationPresenter
{
Configuration configuration = new Configuration();
IConfigurationView view;
public ConfigurationPresenter(IConfigurationView view)
{
this.view = view;
this.view.SelectConfigurationFile += delegate
{
// The ISelectFilePresenter and ISelectFileView behaviors
// are implicit here, but in a WinForms case, a call to
// OpenFileDialog wouldn't be too far fetched...
var selectFilePresenter = Gimme.The<ISelectFilePresenter>();
selectFilePresenter.ShowView();
this.configuration.FullPath = selectFilePresenter.FullPath;
this.view.SetConfigurationFile(this.configuration.FullPath);
};
}
public void ShowView()
{
this.view.SetConfigurationFile(this.configuration.FullPath);
this.view.Show();
}
}
除上述内容外,我通常还有一个base IView
界面,我在其中存放Show()
和我的视图通常受益的任何所有者视图或视图标题.
To your questions:
1. When the winform loads, it has to obtain a treeview. Am I correct in thinking that the view should therefore call a method such as: presenter.gettree(), this in turn will delegate to the model, which will obtain the data for the treeview, create it and configure it, return it to the presenter, which in turn will pass to the view which will then simply assign it to, say, a panel?
我会从IConfigurationPresenter.ShowView()
打IConfigurationView.SetTreeData(...)
,就在打IConfigurationView.Show()
之前
2. Would this be the same for any data control on the Winform, as I also have a datagridview?
是的,我会打IConfigurationView.SetTableData(...)
.由视图决定给定数据的格式.演示者只需遵守视图的约定,即它需要表格数据.
3. My App, has a number of model classes with the same assembly. It also supports a plugin architecture with plugins that need to be loaded at startup. Would the view simply call a presenter method, which in turn would call a method that loads the plugins and display the information in the view? Which tier would then control the plugin references. Would the view hold references to them or the presenter?
如果插件与视图相关,那么视图应该知道它们,而不是演示者.如果它们都是关于数据和模型的,那么视图就不应该与它们有任何关系.
4. Am I correct in thinking that the view should handle every single thing about presentation, from treeview node colour, to datagrid size, etc?
对可以将其视为提供描述数据的XML的演示者,以及获取数据并对其应用CSS样式表的视图.具体来说,演示者可能会调用IRoadMapView.SetRoadCondition(RoadCondition.Slippery)
,然后视图会将道路渲染为红色.
What about data for clicked nodes?
5. If when I click on the treenodes, should I pass through the specific node to the presenter and then from that the presenter would work out what data it needs and then asks the model for that data, before presenting it back to the view?
如果可能的话,我会一次性传递在视图中呈现树所需的所有数据.但是,如果一些数据太大,无法从一开始就传递,或者如果它本质上是动态的,需要模型(通过演示者)提供"最新快照",那么我会在视图界面中添加类似于event LoadNodeDetailsEventHandler LoadNodeDetails
的内容,以便演示者可以订阅它,从模型中获取LoadNodeDetailsEventArgs.Node
中 node 的详细信息(可能是通过其某种ID),以便在事件处理程序委托返回时,视图可以更新其显示的 node 详细信息.请注意,如果获取数据的速度太慢,无法获得良好的用户体验,则可能需要这种异步模式.