如何获取任意事件的调用列表

发布于 2024-12-25 11:34:25 字数 394 浏览 4 评论 0原文

如何获取WPF中控件的委托列表表单事件。

我已尝试以下代码,但它将返回字段信息为空

TextBox cont = new TextBox();
cont.TextChanged += new TextChangedEventHandler(cont_TextChanged);
FieldInfo fi = cont.GetType().GetField("TextChanged", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static);
Delegate del = (Delegate)fi.GetValue(cont);

How to get the delegate list form event of the control in WPF.

I have tried the following code but it will return the field info as null

TextBox cont = new TextBox();
cont.TextChanged += new TextChangedEventHandler(cont_TextChanged);
FieldInfo fi = cont.GetType().GetField("TextChanged", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.Public | BindingFlags.Static);
Delegate del = (Delegate)fi.GetValue(cont);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

西瑶 2025-01-01 11:34:25

我不知道为什么人们说这是不可能的:

假设您想临时禁用任何事件,您可以创建一个这样的方法:

static Delegate[] DisableEvents(this Control ctrl, string eventName)
{
        PropertyInfo propertyInfo = ctrl.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
        EventHandlerList eventHandlerList = propertyInfo.GetValue(ctrl, new object[] { }) as EventHandlerList;
        FieldInfo fieldInfo = typeof(Control).GetField("Event"+eventName, BindingFlags.NonPublic | BindingFlags.Static);

        object eventKey = fieldInfo.GetValue(ctrl);
        var eventHandler = eventHandlerList[eventKey] as Delegate;
        Delegate[] invocationList = eventHandler.GetInvocationList();
        foreach (EventHandler item in invocationList)
        {
            ctrl.GetType().GetEvent(eventName).RemoveEventHandler(ctrl, item);
        }
        return invocationList;

}|

您可以这样调用它:

var events = textbox1.DisableEvents("GotFocus")

如果您想再次添加它们,您只需要通过事件列表。

I dont know why the people say it's not possible:

Lets say you want to disable any event temporary, you can create a method like this:

static Delegate[] DisableEvents(this Control ctrl, string eventName)
{
        PropertyInfo propertyInfo = ctrl.GetType().GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
        EventHandlerList eventHandlerList = propertyInfo.GetValue(ctrl, new object[] { }) as EventHandlerList;
        FieldInfo fieldInfo = typeof(Control).GetField("Event"+eventName, BindingFlags.NonPublic | BindingFlags.Static);

        object eventKey = fieldInfo.GetValue(ctrl);
        var eventHandler = eventHandlerList[eventKey] as Delegate;
        Delegate[] invocationList = eventHandler.GetInvocationList();
        foreach (EventHandler item in invocationList)
        {
            ctrl.GetType().GetEvent(eventName).RemoveEventHandler(ctrl, item);
        }
        return invocationList;

}|

You can call it like this:

var events = textbox1.DisableEvents("GotFocus")

If you want to add them again you just need to go through the events list.

探春 2025-01-01 11:34:25

前面的答案中描述的方法非常有效。
但是,要使用它,您需要确保事件不是作为字段实现,而是作为属性实现。同时,对委托的引用存储在Dictionary类的内部对象中。
您可以在此处阅读更多信息:如何:使用字典存储事件实例(C# 编程指南)

The approach described in the previous answer works perfectly.
However, to use it, you need to be sure that the event is implemented not as a field, but as a property. At the same time, the reference to the delegate is stored in the internal object of the Dictionary class.
You can read more here: How to: Use a Dictionary to Store Event Instances (C# Programming Guide)

失去的东西太少 2025-01-01 11:34:25

正如 Kenneth J. Sanchez Venegas 所推荐的,反射是获取类外事件调用列表的唯一方法。但是,当性能很重要时,我们可以使用已编译的 lambda 来创建一个帮助程序,如下所示:

public class EventHelper<TClass, TDelegate> where TDelegate : Delegate
{
    public EventHelper(string eventName)
    {
        var fieldInfo = typeof(TClass).GetField(eventName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) ??
                throw new ArgumentException("Event was not found", nameof(eventName));

        var thisArg = Expression.Parameter(typeof(TClass));
        var body = Expression.Convert(Expression.Field(thisArg, fieldInfo), typeof(TDelegate));
        Get = Expression.Lambda<Func<TClass, TDelegate?>>(body, thisArg).Compile();
    }

    public Func<TClass, TDelegate?> Get { get; }

    public IEnumerable<TDelegate> GetInvocationList(TClass forInstance)
    {
        var eventDelegate = Get(forInstance);
        if (eventDelegate is null)
            yield break;

        foreach (var d in eventDelegate.GetInvocationList())
            yield return (TDelegate)d;
    }
}

假设我们将拥有此帮助程序的一个实例并每次都使用它:

private static readonly EventHelper<JsonSerializer, EventHandler<ErrorEventArgs>> _errorHelper = new(nameof(JsonSerializer.Error));
...

JsonSerializerSettings settings = new();
foreach (var errorHandler in _errorHelper.GetInvocationList(serializer))
    settings.Error += errorHandler;

...

*我正在使用此代码从 Json.NET JsonSerializer 中提取设置因此示例取自该上下文

**使用 C# 9.0 语法功能的代码示例,在 .NET 5 和 .NET 6 上进行了测试。

Reflection, as recommended by Kenneth J. Sanchez Venegas, is the only way to get an invocation list of event outside of a class. But when performance is important, we can make a helper with compiled lambdas like this:

public class EventHelper<TClass, TDelegate> where TDelegate : Delegate
{
    public EventHelper(string eventName)
    {
        var fieldInfo = typeof(TClass).GetField(eventName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) ??
                throw new ArgumentException("Event was not found", nameof(eventName));

        var thisArg = Expression.Parameter(typeof(TClass));
        var body = Expression.Convert(Expression.Field(thisArg, fieldInfo), typeof(TDelegate));
        Get = Expression.Lambda<Func<TClass, TDelegate?>>(body, thisArg).Compile();
    }

    public Func<TClass, TDelegate?> Get { get; }

    public IEnumerable<TDelegate> GetInvocationList(TClass forInstance)
    {
        var eventDelegate = Get(forInstance);
        if (eventDelegate is null)
            yield break;

        foreach (var d in eventDelegate.GetInvocationList())
            yield return (TDelegate)d;
    }
}

Assuming we will have one instance of this helper and use it every time:

private static readonly EventHelper<JsonSerializer, EventHandler<ErrorEventArgs>> _errorHelper = new(nameof(JsonSerializer.Error));
...

JsonSerializerSettings settings = new();
foreach (var errorHandler in _errorHelper.GetInvocationList(serializer))
    settings.Error += errorHandler;

...

*I'm using this code to extract settings from Json.NET JsonSerializer so examples are taken from that context

**Code examples using C# 9.0 syntax features, tested on .NET 5 and .NET 6.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文