winforms 何时以及如何使用带有MVP和依赖注入的Windows窗体创建演示者

wwwo4jvm  于 2022-12-19  发布在  Windows
关注(0)|答案(1)|浏览(110)
    • bounty将在3天后过期**。回答此问题可获得+50的声望奖励。jrn6270正在寻找规范答案:对这个问题的回答很好,提到了细节.

这是一个关于使用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? */)
    }
}
koaltpgm

koaltpgm1#

你的问题很宽泛,在这样一篇文章中不容易回答。你问的是整体UI架构,可能是因为你想模块化你的用户界面。这通常很难用Winforms来实现,因为根据它的核心设计,所有的东西都附在主窗口上,视图很难与组件(如表示器或视图模型)分离。
如果您希望实现UI的模块化,我建议您将技术切换到Windows Presentation Framework(WPF),它具有更好的模块化体系结构,并支持MVP、MVVM、事件隧道等。
如果你想学习如何构建模块化的应用程序,一个很好的起点可能是prism库,它突出了大部分的概念。你也会找到关于如何使用依赖注入,如何创建表示器等的答案。请看这里:https://prismlibrary.com/docs/wpf/view-composition.html

相关问题