c# - 我可以使用反射取消订阅系统事件吗?

标签 c# winforms

我需要创建一个 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)

该处理程序不是虚拟的,因此我无法覆盖它。该处理程序是私有(private)的,因此我无法执行简单的 -= 取消订阅。我已经研究过使用反射来删除处理程序,但我无法让它工作 - 这就是我到目前为止所拥有的;

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]);

并且不会有异常(exception),但我相信它会默默地失败,因为如果我尝试这样访问委托(delegate);

list[eventObj].ToString()

我收到 NullReferenceException,因为 EventHandlerList 中没有这样的对象键。我在 MyTextBox 变得可见后调用 UnsubscribeUserPreferenceChanged(),因此处理程序应该在列表中,因为它是在 OnHandleCreated 中为 RichTextBox 添加的。

有人知道如何取消订阅与父类(super class)中的私有(private)事件处理程序 Hook 的 SystemEvent 吗?

最佳答案

一旦您知道方法名称,由于以下方便的 CreateDelegate ,这很容易过载:

public static Delegate CreateDelegate(
    Type type,
    object target,
    string method
)

所以有问题的代码可能是这样的:

private void UnsubscribeUserPreferenceChanged()
{
    var handler = (UserPreferenceChangedEventHandler)Delegate.CreateDelegate(
        typeof(UserPreferenceChangedEventHandler), this, "UserPreferenceChangedHandler");
    SystemEvents.UserPreferenceChanged -= handler;
}

关于c# - 我可以使用反射取消订阅系统事件吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39980299/

相关文章:

c# - 修改数据库C#中的数据

c# - ASP.NET MVC 查询的通用处理程序

c# - 存储有关 richtextbox 文本的所有信息并重建它 - c# winforms

c# - 文本框验证 #2

c# - 确保用户只能保存在文件夹内

c# - 如何在枚举上创建扩展方法 (c#)

c# - 映射到同一个表的 EF CORE 多个属性

带链接的 C# WPF 文本

wpf - 是否会不赞成使用Windows窗体而使用WPF?

c# - 让 MaskedTextBox 只接受字母