C# MVP、Winforms-事件处理程序或委托

C# MVP、Winforms-事件处理程序或委托,c#,winforms,mvp,C#,Winforms,Mvp,我已经在一些使用被动视图的WinForms应用程序中实现了MVP模式。我以Action和Func的形式实现了一个包含属性和委托的界面,以便在具体视图中连接UI事件并调用演示者 我即将开始一个新的项目,并在网上对模式做了一些研究,包括这里的许多模式示例,并注意到所有的事件处理程序都使用EventHandler通知演示者 我真的不明白为什么在这种情况下会使用事件,因为我认为视图只有一个演示者 我的问题是,这是为了与.Net framework使用事件的方式保持一致,还是为了我没有看到的其他原因 下面

我已经在一些使用被动视图的WinForms应用程序中实现了MVP模式。我以Action和Func的形式实现了一个包含属性和委托的界面,以便在具体视图中连接UI事件并调用演示者

我即将开始一个新的项目,并在网上对模式做了一些研究,包括这里的许多模式示例,并注意到所有的事件处理程序都使用EventHandler通知演示者

我真的不明白为什么在这种情况下会使用事件,因为我认为视图只有一个演示者

我的问题是,这是为了与.Net framework使用事件的方式保持一致,还是为了我没有看到的其他原因

下面是我使用的模式的一个简单示例:

public interface IViewAbstraction
{
    public ModelData ModelData { set; }
    public Action<ModelData> ModelDataChangedCallback { set; }
}

public class SomeWinForm : Form, IViewAbstraction
{
    private Action<ModelData> modelDataChanged;
    private ModelData model;

    public ModelData ModelData
    {
        set { /* when this property changes, update UI */ }
    }

    public Action<ModelData> ModelDataChangedCallback
    {
        set { modelDataChanged = value; }
    }

    private void OnSomeWinformsEvent(EventArgs args)
    {
        if (modelDataChanged == null) throw new Exception();

        modelDataChanged(model);
    }
}

public class Presenter
{
    private readonly IViewAbstraction view;
    private readonly IDataLayerAbstraction dataLayer;

    public Presenter(IViewAbstraction view, IDataLayerAbstraction dataLayer)
    {
        this.dataLayer = dataLayer;
        this.view = view;
        this.view.ModelDataChangedCallback = OnModelChanged;
        this.view.ModelData = dataLayer.GetData();
    }

    private void OnModelChanged(ModelData data)
    {
        // validate and save data.
    }
}
公共接口IViewAbstraction
{
公共模型数据模型数据{set;}
公共操作模型DataChangedCallback{set;}
}
公共类SomeWinForm:Form,IViewAbstraction
{
改变了私人行动模式;
私有模型数据模型;
公共模型数据模型数据
{
设置{/*当此属性更改时,更新UI*/}
}
公共操作模型DataChangedCallback
{
设置{modelDataChanged=value;}
}
SomeWinFormSevent上的私有无效(EventArgs args)
{
如果(modelDataChanged==null)抛出新异常();
模型数据更改(模型);
}
}
公开课主持人
{
私有只读IViewAbstraction视图;
专用只读IDataLayerStrAction数据层;
公共演示者(IViewAbstraction视图,IDataLayerStrAction数据层)
{
this.dataLayer=数据层;
this.view=视图;
this.view.ModelDataChangedCallback=OnModelChanged;
this.view.ModelData=dataLayer.GetData();
}
ModelChanged上的私有void(ModelData数据)
{
//验证并保存数据。
}
}

您的模式与使用事件基本相同,但有一个关键区别。事件不公开基础委托(在您的示例中为ModelDataChangedCallback)。公开这是不好的做法,因为其他代码可以清除调用列表。事件将具有一个基础委托,该委托可以添加到类中或从中删除,但决不能从类的作用域之外清除

我不理解你关于没有多个订阅者的观点——这不是不使用事件的理由。事件只是类说“嘿!这件事已经发生了”的一种方式,使用Presenter对象进行1对1映射是完全合理和正常的


您也不会在视图中看到外观非常奇怪的只写属性。

同意只写属性,当我看到它们时,它会让我感到厌烦,并添加了比复杂视图更多的样板代码。但是当使用事件时,他必须创建一个特定的
ModelDataChangedEventArgs
类,以包含演示者需要处理的数据,对吗?当有很多事件发生时,锅炉板等级的数量将会爆炸。所有
操作MyDelegate
都必须更改为
事件处理程序MyEvent
…因为它是1:1映射,所以清除调用列表的概率应该非常有限…