如何在没有访问权限的情况下覆盖继承控件的事件?
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");
}
}
我正在从事一个项目,在该项目中我实际上使用具有某些自动化行为的继承控件,因此我不需要重新完成所有工作。这些控件是从 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");
}
}