如何在 C# 中使用 MVC 模式处理事件

How to handle events with MVC Pattern in C#

我正在使用 MVC 架构模式在 C# 中实现一个小程序。该程序的目标是通过必须处理按钮单击事件的控制器单击按钮(在视图中)来更新鼠标单击计数器(在模型中)的值。

到目前为止我写的代码是有效的(它编译没有错误),但是如果无法处理按钮单击事件,因为我无法弄清楚我必须将哪种代码放入视图以及放入什么控制器。我尝试并发现可行的唯一解决方案是为视图提供对其控制器的引用。这样,事件处理程序在视图中注册和实现,并调用控制器的方法(例如Controller.DoSomethingOnButtonClick())。但是这个解决方案打破了 MVC 模式,因为据我所知,View 不应该知道它的 Controller。

模型(实现观察者模式,即"observable"):

class Model : Subject
{
   private int counter = 0;

   public void IncreaseCounterByOne()
   {
      counter++;
      Notify(); // notify the observers
   }

   public int GetCounter()
   {
      return counter;
   }
}

View(实现了观察者模式,就是"observer"):

class View : IObserver
{
    private Model Model;
    private Form MyForm = new Form();
    private Label MyLabel = new Label();
    private Button MyButton = new Button();

    public View(Model model)
    {
        this.Model = model;
        this.Model.Attach(this);
    }

    public void CreateView()
    {
        // create and display the view (MyForm, MyLabel, MyButton)
    }

    public void Update(Subject subject)
    {
        UpdateLabel();
    }

    private void UpdateLabel()
    {
        MyLabel.Text = "Click Counter: " + Model.GetCounter();
    }
}

控制者:

class Controller
{
    private Model Model;
    private View View;

    public Controller(Model model, View view)
    {
        this.Model = model;
        this.View = view;

        this.View.CreateView();
    }

    private void UpdateCounter()
    {
        this.Model.IncreaseCounterByOne();
    }
}

我想要实现的是控制器捕获由 MyButton 生成的按钮单击事件并在其事件处理程序中处理它,我假设它是这样的:

public void OnButtonClicked(object sender, EventArgs e)
{
    UpdateCounter();
}

如何在不使用对控制器的引用的情况下完成此操作?可能吗?

PS。我已经阅读了很多类似的问题,但没有找到我正在寻找的解决方案。

您 运行 遇到了一个问题,其中像 MVC 这样的模式的微不足道的例子失败了:UI 通常同时扮演 V 和 C 的角色 - 它显示数据并提供一种方法操纵它。如果您的示例涉及更多(例如,网络服务是控制器),那么关注点将更容易分开

从逻辑上讲,分离仍然存在,但是当您实际上试图将它合并到同一个 UI - 但你不应该担心这个

接受您的 UI 包含您的视图并且还包含您的控制器,因此 UI class(es) 的工作是统一所有的东西。考虑到您的标签实际上是视图,而不是您的 class 恰好称为视图。您需要获得的概念欣赏是您可以通过控制器使用 3 种不同的方式来更改模型(计时器、按钮、您向其发送一些数据的 tcp 套接字)和 3 种不同的可视化方式(标签显示一个数字,一个进度条,一个网页调用 returns 一串 'A' 与当前计数器一样长)并且你已经分离了你的关注点 - label/progbar/website 是独立的timer/button/website 并且它们彼此不了解,它们不交互,您不需要将一个引用传递给另一个以使一切正常运行。您可以移除按钮和插座,计时器将继续导致模型操作 label/progbar 将继续显示