【问题标题】:Handle menu event in C# MVP在 C# MVP 中处理菜单事件
【发布时间】:2021-11-07 07:58:56
【问题描述】:

我正在学习 C# 和 MVP。我能够处理简单的菜单点击事件。我正在尝试使用 MVP 模式处理菜单点击事件,但无法弄清楚它为什么不起作用。我在互联网上查看了很多代码并想出了以下内容。

interface IMenuBarView
{
    event EventHandler AboutMenuItemClicked;
    ...
}

public partial class MenuBarView : UserControl, IMenuBarView
{
    public event EventHandler AboutMenuItemClicked;
    private MenuBarPresenter m_menuBarPresenter;

    public MenuBarView()
    {
        this.aboutToolStripMenuItem.Click += AboutMenuItemClicked;
        m_menuBarPresenter = new MenuBarPresenter(this);
    }
}

class MenuBarPresenter
{
    private IMenuBarView m_menuView;

    public MenuBarPresenter(IMenuBarView menu)
    {
        m_menuView = menu;
        m_menuView.AboutMenuItemClicked += AboutMenuItemClicked;
    }
    public  void AboutMenuItemClicked(object sender, EventArgs e)
    {
        MessageBox.Show("Hello");
    }
}

我可以在 MenuBarView 中有一个事件处理程序,然后它可以调用演示者来执行逻辑。但我更感兴趣的是做上面的那一项。这不是正确的做法吗? 我对 C# 真的很陌生,所以不要杀了我。 :)

编辑后: 我很快编造了一些我尝试按照@Enigmativity cmets 编译的东西。它运行但从未调用该事件。创建一个表单,添加一个菜单项并将菜单项名称命名为 item1ToolStripMenuItem。单击菜单时,不会触发该事件。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace testEventHandler
{

    public partial class Form1 : Form, IMenuBarView
    {
        public event EventHandler AboutMenuItemClicked;
        private MenuBarPresenter m_menuBarPresenter;

        public Form1()
        {
            InitializeComponent();

            this.item1ToolStripMenuItem.Click += AboutMenuItemClicked;
            m_menuBarPresenter = new MenuBarPresenter(this);
        }


    }

    interface IMenuBarView
    {
        event EventHandler AboutMenuItemClicked;
    }

    class MenuBarPresenter
    {
        private IMenuBarView m_menuView;
        public MenuBarPresenter(IMenuBarView menu)
        {
            m_menuView = menu;
            m_menuView.AboutMenuItemClicked += item1ToolStripMenuItem_Click;
        }
        private void item1ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("hello");
        }
    }
}

【问题讨论】:

  • 如果您发布的代码能够真正编译,那将非常有用,而且很高兴知道除此之外,“不工作”对您的实际代码意味着什么。
  • 我想发布最少数量的代码,这样任何人都可以判断这是否是一个好代码。不工作意味着我没有在 AboutMenuItemClicked 中获得控件。
  • “我没有在 AboutMenuItemClicked 中获得控件”是什么意思?
  • 另外,您应该发布minimal reproducible example。最少的代码是好的,只要它包含足以让我们看到您面临的问题的所有内容。

标签: c# mvp


【解决方案1】:

您的命令顺序有问题。

当你写这个时:

        this.item1ToolStripMenuItem.Click += this.AboutMenuItemClicked;

您是在说“任何附加到this.AboutMenuItemClicked 的处理程序都应该复制this.item1ToolStripMenuItem.Click”。当时没有附加的处理程序。你没有复制任何东西。

然后你调用m_menuBarPresenter = new MenuBarPresenter(this);item1ToolStripMenuItem_Click 附加到this.AboutMenuItemClicked 事件委托。

如果你交换它的工作顺序:

        m_menuBarPresenter = new MenuBarPresenter(this);
        this.item1ToolStripMenuItem.Click += this.AboutMenuItemClicked;

但是,这不是附加事件的正确方法。您不需要关心是否有人已附加或处理程序。

        this.item1ToolStripMenuItem.Click += (s, e) => this.AboutMenuItemClicked?.Invoke(s, e);
        m_menuBarPresenter = new MenuBarPresenter(this);

这是正确的方法。

如果有订阅者,?.Invoke 会调用 .Invoke,但如果没有订阅者,它什么也不做。


我也玩过你的代码。这更接近于我做 MVP 的方式:

public partial class Form1 : Form
{
    public event EventHandler AboutMenuItemClicked;
    private Presenter _presenter;
    public Form1()
    {
        InitializeComponent();

        this.item1ToolStripMenuItem.Click += (s, e) => this.AboutMenuItemClicked?.Invoke(s, e);

        _presenter = new Presenter(this);
    }

    public void ShowMessage(string message)
    {
        MessageBox.Show(message);
    }
}

interface IMenuBarView
{
    event EventHandler AboutMenuItemClicked;
}

class Presenter
{
    private readonly Form1 _form;
    private readonly AlertModel _alertModel;

    public Presenter(Form1 form)
    {
        _form = form;
        _form.AboutMenuItemClicked += _form_AboutMenuItemClicked;
        _alertModel = new AlertModel();
        _alertModel.Message += _alertModel_Message;
    }

    private void _alertModel_Message(object sender, string e)
    {
        _form.ShowMessage(e);
    }

    private void _form_AboutMenuItemClicked(object sender, EventArgs e)
    {
        _alertModel.UpdateModel("About Menu Item");
    }
}

class AlertModel
{
    public event EventHandler<string> Message;

    public void UpdateModel(string action)
    {
        this.Message?.Invoke(this, $"User has selected \"{action}\"");
    }
}

【讨论】:

  • 更改顺序有效!如果我想了解它,这个结构叫什么? this.item1ToolStripMenuItem.Click += (s, e) => this.AboutMenuItemClicked?.Invoke(s, e);我得到了你的代码版本。我认为从视图 -> 演示者 -> 模型 -> 演示者 -> 视图的完整流程。错过一些东西的机会更少。我想我需要一段时间才能习惯。
  • @nav - 查找匿名函数。
猜你喜欢
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-05
  • 2011-11-20
  • 1970-01-01
相关资源
最近更新 更多