这是一个关于使用 Lamar 进行依赖注入(inject) (DI) 的问题,Windows 窗体 (C#) 使用 model-view-presenter (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);
这将解决我的演示者和 View 可能具有的任何依赖关系。
对于 MVP 模式,我使用观察演示者风格,对此进行了解释 here 。我喜欢这种特定的风格,因为它完全将演示者的知识与观点脱钩。可以找到这样的示例 here .
这意味着我的 View (表单和用户控件)的构造函数不接受任何参数。这使我可以在设计表单时将用户控件拖放到表单中。
例如,如果我的 MainView(这是一个表单)中有一个选项卡控件,我可以将 SubView(这是一个用户控件)拖放到选项卡控件的选项卡页中。
所有逻辑(要呈现什么数据等)都在呈现器中处理。这意味着我的演示者构造函数将域项目中的接口(interface)以及具体 View 的接口(interface)作为参数。
我的主要观点:
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 :
- 演示者没有任何 View 可以调用的方法,但 View 有演示者可以订阅的事件。
- 演示者知道自己的观点。这是通过使用构造函数注入(inject)来完成的。
- View 不知道哪个演示者在控制它。
问题
基于 MVP 和 DI 的实现,我如何以及何时创建我的演示者?它们依赖于域项目的接口(interface),这就是它们在 lamar-container 中使用的原因。我应该打电话var mainPresenter = new MainPresenter(container.GetRequiredService<IMainView>(), /* get service for all required interfaces*/);
对于 Program.cs 中的所有演示者?
我是否误解了有关 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 的其他实现,其中演示者是在具体 View 的构造函数中创建的,但是如何将必要的接口(interface)传递给演示者? 例如:
public partial class MainView : Form, IMainView
{
public MainView()
{
InitializeComponent();
var presenter = new MainPresenter(this, /* How to pass interfaces here? */)
}
}
最佳答案
您的问题非常广泛,在这样的帖子中不容易回答。您询问整体 UI 架构,可能是因为您想要模块化您的用户界面。这对于 Winforms 通常很难实现,因为根据其核心设计,所有内容都附加到主窗口,并且 View 很难与演示者或 View 模型等组件解耦。
如果您想实现 UI 的模块化,我建议您将技术切换到 Windows 演示框架 (WPF),它具有更好的模块化架构,并支持 MVP、MVVM、事件隧道等。
如果您想研究如何构建模块化应用程序,棱镜库可能是一个很好的起点,它突出了大多数概念。您还将找到有关如何使用依赖项注入(inject)、如何创建演示者等的答案。请查看此处:https://prismlibrary.com/docs/wpf/view-composition.html
关于c# - 何时以及如何使用带有 MVP 和依赖项注入(inject)的 Windows 窗体创建演示者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74763629/