c# - 何时以及如何使用带有 MVP 和依赖项注入(inject)的 Windows 窗体创建演示者

标签 c# winforms dependency-injection mvp lamar

这是一个关于使用 Lamar 进行依赖注入(inject) (DI) 的问题,Windows 窗体 (C#) 使用 model-view-presenter (MVP) 模式以及如何(以及何时)初始化演示者对象。

我有一个分为三个项目的解决方案:

  1. 基础设施
  2. 域名
  3. 演示

在演示项目中,我有表单和用户控件,它们使用 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/

相关文章:

c# - 填充 ListBox 时从每个列表项中删除前 12 个字符

c# - 如何将字节数组转换为 DataGridView 的字符串

vb.net - 如何解决幻像断点?

c# - Unity - 通过 XML 的工厂

c# - 防止更改 String.Empty 的值

c# - Azure 网站上的 "DataReader.GetFieldType(...) returned null"

c# - 在类之间重用代码

c# - 使用 Parallel.ForEach 对多线程的依赖

java - 使用 Builder 模式为客户端库注入(inject) Guice

c# - 无法捕捉屏幕