这是一个关于使用Lamar的依赖注入(DI)、使用model-view-presenter(MVP)模式的Windows窗体(C#)以及如何(以及何时)初始化演示者对象的问题。
我的解决方案分为三个项目:
1.基础设施
1.领域
1.列报
在演示项目中,我有窗体和用户控件,它们使用MVP模式分隔。
在演示项目的Program.cs文件中,我使用Lamar定义了我的容器,并将主视图创建为:
var container = new Container(x =>
{
x.AddSingleton<IInterfaceFromDomainProject, ClassFromDomainProject>();
x.AddSingleton<IMainView, MainView>();
x.AddSingleton<IMainPresenter, MainPresenter>();
x.AddSingleton<ISubView, SubView>();
x.AddSingleton<ISubPresenter, SubPresenter>();
});
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var mainView = new MainView();
Application.Run(mainView);
这将解决演示文稿和视图可能具有的任何依赖项。
对于MVP模式,我使用的是 * 观察演示者风格 *,这在here中有解释。我喜欢这种特定的风格,因为它完全将演示者的知识与视图分离。可以在here中找到这样的一个示例。
这意味着我的视图(窗体和用户控件)的构造函数不需要任何参数。这允许我在设计窗体时将用户控件拖放到窗体中。
例如,如果我的主视图(一个窗体)中有一个选项卡控件,我可以将子视图(一个用户控件)拖放到选项卡控件的选项卡页中。
所有的逻辑(显示什么数据等)都在presenters中处理,这意味着我的presenters构造函数将域项目的接口作为参数,以及具体视图的接口。
我的主要观点:
public interface IMainView
{
event EventHandler MyCustomEvent;
void ShowMessage();
}
public partial class MainView : Form, IMainView
{
public event EventHandler MyCustomEvent;
public MainView()
{
InitializeComponent();
}
private void button_Click(object sender, EventArgs e)
{
MyCustomEvent.Invoke(sender, EventArgs.Empty);
}
public void ShowMessage()
{
MessageBox.Show("Hello!");
}
}
我的主讲人:
public interface IMainPresenter
{
void ShowMessageHandler(object sender, EventArgs e);
void ShowData();
}
public class MainPresenter: IMainPresenter
{
private readonly IMainView _view;
private readonly IInterfaceFromDomainProject _foo;
public MainPresenter(IMainView view, IInterfaceFromDomainProject foo)
{
_view = view;
_foo = foo;
_view.MyCustomEvent += ShowMessageHandler;
}
public void ShowMessageHandler(object sender, EventArgs e)
{
_view.ShowMessage();
}
public void ShowData()
{
// Do something with _foo. Get data and display it in its view.
}
}
从以前的link:
- 演示者没有视图可以调用的任何方法,但视图具有演示者可以订阅的事件。
- 表示器知道它的视图,这是通过构造函数注入实现的。
- 视图不知道哪个演示者正在控制它。
- 问题**
基于MVP和DI的这个实现,我如何以及何时创建我的演示者?它们依赖于来自域项目的接口,这就是为什么它们被用在lamar容器中。我应该为Program.cs中的所有演示者调用var mainPresenter = new MainPresenter(container.GetRequiredService<IMainView>(), /* get service for all required interfaces*/);
吗?
我是不是误解了DI或MVP模式?
- 编辑**
var mainPresenter = new MainPresenter(container.GetRequiredService<IMainView>() /* get service for all required interfaces*/);
不起作用,我收到一个NullReferenceException:MyCustomEvent.Invoke(sender, EventArgs.Empty);
上的"对象引用未设置为对象的示例。"(我知道我应该使用?.
)。
唯一的方法是调用:
var mainView = new MainView();
var mainPresenter = new MainPresenter(mainView);
我见过MVP的其他实现,其中表示器是在具体视图的构造函数中创建的,但是我如何将必要的接口传递给表示器呢?
public partial class MainView : Form, IMainView
{
public MainView()
{
InitializeComponent();
var presenter = new MainPresenter(this, /* How to pass interfaces here? */)
}
}
1条答案
按热度按时间koaltpgm1#
你的问题很宽泛,在这样一篇文章中不容易回答。你问的是整体UI架构,可能是因为你想模块化你的用户界面。这通常很难用Winforms来实现,因为根据它的核心设计,所有的东西都附在主窗口上,视图很难与组件(如表示器或视图模型)分离。
如果您希望实现UI的模块化,我建议您将技术切换到Windows Presentation Framework(WPF),它具有更好的模块化体系结构,并支持MVP、MVVM、事件隧道等。
如果你想学习如何构建模块化的应用程序,一个很好的起点可能是prism库,它突出了大部分的概念。你也会找到关于如何使用依赖注入,如何创建表示器等的答案。请看这里:https://prismlibrary.com/docs/wpf/view-composition.html