我需要创建一个RichTextBox子类,该子类除了不订阅UserPreferenceChanged之外,在所有方面都是相同的。此事件导致我的应用挂起。我必须使用RichTextBox,但无法将其交换为MultiLine=True的TextBox或其他类似情况。
这是System.Windows.Forms.RichTextBox订阅的位置;
protected override void OnHandleCreated(EventArgs e)
{
...
SystemEvents.UserPreferenceChanged += new UserPreferenceChangedEventHandler(this.UserPreferenceChangedHandler);
}
这是经办人的签名;
private void UserPreferenceChangedHandler(object o, UserPreferenceChangedEventArgs e)
这个句柄不是虚拟的,所以我不能覆盖它。这个句柄是私有的,所以我不能用一个简单的 -= 来取消订阅。我已经考虑过使用反射来移除这个句柄,但是我不能让它工作--这是我目前所做的;
public partial class MyRichTextBox : RichTextBox
{
...
private void UnsubscribeUserPreferenceChanged()
{
FieldInfo fieldInfo = typeof(SystemEvents).GetField("OnUserPreferenceChangedEvent", BindingFlags.NonPublic | BindingFlags.Static);
// fieldInfo.ToString() = "System.Object.OnUserPreferenceChangedEvent"
object eventObj = fieldInfo.GetValue(this);
// eventInfo.ToString() = "System.Object"
PropertyInfo propInfo = typeof(RichTextBox).GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);
// propInfo.ToString() = "System.ComponentModel.EventHandlerList Events"
EventHandlerList list = (EventHandlerList)propInfo.GetValue(this, null);
// list.ToString() = "System.ComponentModel.EventHandlerList"
...
现在我可以跟注
list.RemoveHandler(eventObj, list[eventObj]);
也不会有例外,但我相信它是无声的失败,因为如果我试图访问委托;
list[eventObj].ToString()
我收到NullReferenceException,因为EventHandlerList中没有这样的对象键。我在MyTextBox变为可见后调用UnsubscribeUserPreferenceChanged(),因此处理程序应该在列表中,因为它是为RichTextBox添加到OnHandleCreated中的。
有人知道如何取消订阅挂接到超类中的私有事件处理程序的SystemEvent吗?
4条答案
按热度按时间lb3vh1jj1#
一旦知道了方法名,就非常容易了,因为有下面的
CreateDelegate
重载:所以这个代码可能是这样的:
af7jpaap2#
您应该使用
Type.GetEvent
而不是Type.GetField
。只有这样,您才能在运行时删除它:
db2dz4w83#
对于常规控件,而不是RichtTextBox,我也遇到了同样的问题。Ivan Stoev的代码变成了这样:
它从SystemEvents取消订阅Control.UserPreferenceChanged(私有)方法。
g6baxovj4#
我找到了一种修复方法,通过迭代订阅systemevents的所有对象,然后在执行时取消订阅。它是上述方法和另一个代码的组合,我发现该代码捕获应用中所有对象注册的所有系统事件