public interface IView<TPresenter>
{
TPresenter Presenter { get; set; }
}
public interface IPresenter<TView, TPresenter>
where TView : IView<TPresenter>
where TPresenter : IPresenter<TView, TPresenter>
{
TView View { get; set; }
}
那么这个抽象的演示者类:
public abstract class AbstractPresenter<TView, TPresenter> : IPresenter<TView, TPresenter>
where TView : IView<TPresenter>
where TPresenter : class, IPresenter<TView, TPresenter>
{
protected TView view;
public TView View
{
get { return this.view; }
set
{
this.view = value;
this.view.Presenter = this as TPresenter;
}
}
}
视图通过属性而不是构造函数注入,以允许设置器中的双向影响 . 请注意,需要安全演员......
然后,我的具体演示者是这样的:
public class MyPresenter : AbstractPresenter<IMyView, MyPresenter>
{
//...
}
It allows you to inject other dependencies (services, repos) into both your view and your presenter. 但是在您描述的场景中,我建议您将服务和缓存注入 presenter ,而不是视图 .
0
在WinForms中,我更喜欢简单的方法 . 通常,您在设计图面上处理一些UserControl - 将它们作为视图类 . .NET为您创建控件层次结构(通过InitializeComponent) . 如果您使用Passive View模式,则每个视图都会实例化它's presenter. (You can do this either directly or by asking an IOC container.) Use constructor injection to pass a reference to the view'与演示者的接口's constructor. The presenter can then wire itself up to view events. Repeat the process for the model: the presenter instantiates a model and wires up to its events. (In this case you don' t需要构造函数注入,因为Passive View表示演示者保留对模型的引用,反之亦然 . )
public interface IView
{
...
event Action SomeEvent;
event EventHandler Disposed;
...
}
// Note that the IView.Disposed event is implemented by the
// UserControl.Disposed event.
public class View : UserControl, IView
{
public event Action SomeEvent;
public View()
{
var presenter = new Presenter(this);
}
}
public interface IModel
{
...
event Action ModelChanged;
...
}
public class Model : IModel
{
...
public event Action ModelChanged;
...
}
public class Presenter
{
private IView MyView;
private IModel MyModel;
public Presenter(View view)
{
MyView = view;
MyView.SomeEvent += RespondToSomeEvent;
MyView.Disposed += ViewDisposed;
MyModel = new Model();
MyModel.ModelChanged += RespondToModelChanged;
}
// You could take this a step further by implementing IDisposable on the
// presenter and having View.Dispose() trigger Presenter.Dispose().
private void ViewDisposed(object sender, EventArgs e)
{
MyView.SomeEvent -= RespondToSomeEvent;
MyView.Disposed -= ViewDisposed;
MyView = null;
MyModel.Modelchanged -= RespondToModelChanged;
MyModel = null;
}
}
4 回答
这是我做的:
首先,我定义了这些接口:
那么这个抽象的演示者类:
视图通过属性而不是构造函数注入,以允许设置器中的双向影响 . 请注意,需要安全演员......
然后,我的具体演示者是这样的:
IMyView
实现了IView
. 必须存在具体的视图类型(例如MyView
),但它是解析它的容器:我在容器中注册
MyPresenter
类型,具有瞬态行为 .我在具有瞬态行为的容器中将
MyView
注册为IMyView
.然后我要求容器
MyPresenter
.容器实例化MyView
它实现
MyPresenter
它通过
AbstractPresenter.View
属性将视图注入到演示者中 .setter代码完成双向关联
容器返回两个Presenter / View
It allows you to inject other dependencies (services, repos) into both your view and your presenter. 但是在您描述的场景中,我建议您将服务和缓存注入 presenter ,而不是视图 .
在WinForms中,我更喜欢简单的方法 . 通常,您在设计图面上处理一些UserControl - 将它们作为视图类 . .NET为您创建控件层次结构(通过InitializeComponent) . 如果您使用Passive View模式,则每个视图都会实例化它's presenter. (You can do this either directly or by asking an IOC container.) Use constructor injection to pass a reference to the view'与演示者的接口's constructor. The presenter can then wire itself up to view events. Repeat the process for the model: the presenter instantiates a model and wires up to its events. (In this case you don' t需要构造函数注入,因为Passive View表示演示者保留对模型的引用,反之亦然 . )
我用这种方法找到的唯一一个就是正确管理模型和演示者的生命周期 . 您希望保持视图尽可能简单,因此您可能不希望它维护对演示者的引用 . 但是,这意味着您已经将此演示者对象与事件处理程序绑定在视图上 . 此设置可防止您的视图被垃圾回收 . 一种解决方案是让您的视图发布一个表明它正在关闭的事件 . 演示者将收到该事件并删除其模型和视图订阅 . 现在,Web中的对象已正确解除引用,垃圾收集器可以完成其工作 .
最终结果如下:
您可以通过使用IOC并向IOC容器询问IModel(在Presenter类中)和IPresenter(在View类中)的实现来进一步解耦此示例 .
WinformsMVP是一个非常好的Windows窗体MVP框架 . 您可以使用此框架轻松地在多个视图中注入服务 . This是一篇很好的文章,带有示例源代码,解释了如何使用该框架 .