这是一个关于使用Lamar的依赖注入(DI), windows窗体(c#)使用模型-视图-演示器(MVP)模式以及如何(以及何时)初始化演示器对象的问题。
我有一个解决方案,分为三个项目:
基础设施- 域
- 表示
在演示项目中,我有表单和用户控件,它们使用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模式,我使用观察演示者样式,在这里解释。我喜欢这种特定的风格,因为它完全将演示者的知识与视图分离。在这里可以找到一个例子。
这意味着视图(窗体和用户控件)的构造函数不接受任何参数。这允许我在设计表单时将用户控件拖放到表单中。
例如,如果我的MainView(这是一个表单)有一个选项卡控件,我可以将SubView(这是一个用户控件)拖放到选项卡控件的选项卡页面中。
所有的逻辑(呈现什么数据等)都在呈现程序中处理。这意味着我的呈现器构造函数从域项目中获取接口作为参数,以及具体视图的接口。
我的主要观点:
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.
}
}
从前面的链接:
- 演示者没有视图可以调用的任何方法,但是视图有演示者可以订阅的事件。
- 主讲人知道自己的视图。这是通过构造函数注入完成的。
- 视图不知道是哪个演示者在控制它
问题
基于MVP和DI的实现,我如何以及何时创建我的演示器?它们依赖于域项目的接口,这就是为什么在层叠容器中使用它们的原因。在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? */)
}
}
你的问题很宽泛,在这样一个帖子里不容易回答。您正在询问总体UI架构,可能是因为您想要模块化用户界面。这在Winforms中很难实现,因为根据其核心设计,所有内容都附加在主窗口上,视图几乎不能与演示器或视图模型等组件解耦。
如果你想实现你的UI模块化,我建议你切换到Windows Presentation Framework (WPF),它有一个更好的,模块化的架构,支持MVP, MVVM,事件隧道和更多。
如果您想学习如何构建模块化应用程序,prism库可能是一个很好的起点,它突出了大多数概念。您还可以找到关于如何使用依赖注入、如何创建演示器等问题的答案。请看这里:https://prismlibrary.com/docs/wpf/view-composition.html