如何在没有访问权限的情况下覆盖继承控件的事件?

How to override an inherited control's event without having access to it?

我正在从事一个项目,在该项目中我实际上使用具有某些自动化行为的继承控件,因此我不需要重新完成所有工作。这些控件是从 DevExpress 控件继承的,我可以访问继承的控件。

我遇到了一个事件被引发并且订阅我自己的方法没有显示任何结果,因为继承的控件执行了它自己的代码。

继承的控件:

private void BinaryGridView_InvalidRowException(object sender, InvalidRowExceptionEventArgs e)
{
    e.ExceptionMode = DevExpress.XtraEditors.Controls.ExceptionMode.NoAction;
    DevExpress.XtraEditors.XtraMessageBox.Show(e.ErrorText, "Atención", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

我的表单中的自己的方法:

grwWhatever.InvalidRowException += (s, e) => { e.ExceptionMode = ExceptionMode.NoAction; };

根据 documentation,我试图隐藏任何消息框,当然,正如我继承的控件源所说,它正在显示该消息框。

所以,我想达到那个点有两个选择:

1.- 从继承的控件继承,将 private 更改为 protected virtual 并覆盖该行为。这不是一个选择,因为我无法在这里解释的原因 我必须唯一地使用那些继承的控件

2.- 将 private 更改为 public,这样我就可以退订并再次订阅,之后:

grwWhatever.InvalidRowException -= grwWhatever.BinaryGridView_InvalidRowException;
grwWhatever.InvalidRowException += (s, e) => { e.ExceptionMode = ExceptionMode.NoAction; };

第二个选项实际上工作正常,但是...让我们猜测其中 none 个是可行的。更改继承控件事件的内容是不可能的。留下一部分继承控件的使用设计...哪种方法最好?可以使用 Reflection 来完成吗?

正确的解决方案应该是更改基础代码 class。但是既然你已经提到你没有权限更改基础代码class,并且使用反射的解决方案也是可以接受的,这里我将分享一个使用反射的示例,用于学习目的.

从基础中删除私有事件处理程序订阅 class

我假设我有一个名为 MyBaseForm 的基础 class,并且您已经使用基础 class 中的 MyBaseForm_Load 私有方法处理了 Load 事件。

在此示例中,在派生自基础 class 的派生 class MyDerivedForm 中,我使用了一些反射代码来删除 MyBaseForm_Load 事件订阅,取而代之,我使用派生的新处理程序处理事件 class MyDerivedForm_Load.

预期行为:

  • 删除事件处理程序之前,您会看到两个消息框
  • 使用 eventInfo.RemoveEventHandler 删除事件处理程序后,您将只看到一个来自派生的 class 事件处理程序的消息框。

代码如下:

public class MyBaseForm : Form
{
    public MyBaseForm()
    {
        this.Load += MyBaseForm_Load;
    }
    private void MyBaseForm_Load(object sender, EventArgs e)
    {
        MessageBox.Show("MyBaseForm_Load");
    }
}

public class MyDerivedForm : MyBaseForm
{
    public MyDerivedForm()
    {
        var eventInfo = this.GetType().GetEvent("Load",
            System.Reflection.BindingFlags.Public |
            System.Reflection.BindingFlags.Instance);
        var delegateType = eventInfo.EventHandlerType;
        eventInfo.RemoveEventHandler(this, 
            Delegate.CreateDelegate(delegateType, this, "MyBaseForm_Load", false, true));

        this.Load += MyDerivedForm_Load;
    }

    private void MyDerivedForm_Load(object sender, EventArgs e)
    {
        MessageBox.Show("MyDerivedForm_Load");
    }
}