【问题标题】:How to override an inherited control's event without having access to it?如何在没有访问权限的情况下覆盖继承控件的事件?
【发布时间】:2019-11-28 08:09:29
【问题描述】:

我正在做一个项目,我实际上在使用具有一些自动化行为的继承控件,因此我不需要重新完成所有工作。控件是从 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; };

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

【问题讨论】:

  • BinaryGridView_InvalidRowException 只是订阅事件,然后您可以将grwWhatever.InvalidRowException 分配给null。在这种情况下,无需将访问器类型更改为public
  • 如果NoAction 的值为ExceptionMode,因为你总是意味着不显示消息框,那么只需转到继承控件并在消息框之前添加 if 语句:if (e.ExceptionMode==ExceptionMode.NoAction).
  • 同样在inherited control中,如果可能的话,最好覆盖OnInvalidRowException进行扩展,而不是有一个事件处理程序。
  • 如果BinaryGridView_InvalidRowException是订阅了继承控件中的事件的事件处理程序,并且您无法更改继承的控件代码,则无法阻止它工作。
  • 是的,有使用反射的解决方案。我将使用Form 类及其Load 事件发布一个示例。

标签: c# .net winforms event-handling


【解决方案1】:

正确的解决方案应该是更改基类中的代码。但既然你提到你无权更改基类的代码,使用反射的解决方案也是可以接受的,这里我将分享一个使用反射的示例,以供学习目的。 p>

从基类中移除私有事件处理程序订阅

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

在此示例中,在派生自基类的派生类 MyDerivedForm 中,我使用一些反射代码来删除 MyBaseForm_Load 事件订阅,而是使用派生类 @ 中的新处理程序处理事件987654326@.

预期行为:

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

代码如下:

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");
    }
}

【讨论】:

  • 就是这样!因为我有源代码,所以我可以选择更改继承控件的代码,但我很好奇在不可能的场景中如何做到这一点。这很摇滚。
  • 如果你可以更改基类代码,最好按照我在问题下发布的cmets :)
猜你喜欢
  • 2010-11-23
  • 1970-01-01
  • 1970-01-01
  • 2021-01-14
  • 2020-10-20
  • 2014-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多