vb.net 检查事件是否至少被触发过一次

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14216892/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 11:49:35  来源:igfitidea点击:

Check if an event has been fired at least once

c#.netvb.netevents

提问by Elmo

I am tracking if an event has been fired like this:

我正在跟踪事件是否像这样被触发:

bool IsFormLoaded;
private void Form1_Load(object sender, EventArgs e)
{
    //Do stuff
    IsFormLoaded = true;
}
private void button1_Click(object sender, EventArgs e)
{
    //Do stuff
}

But doing this for many events is not elegant so I want a solution that lets me check if any event was fired like this:

但是对许多事件这样做并不优雅,所以我想要一个解决方案,让我检查是否有任何事件像这样被触发:

bool IsFormLoaded = IsEventFired(Form1_Loaded);
bool IsButton1Clicked = IsEventFired(Button1_Click);

回答by VladL

You are handling events using designer. You can do it for example in constructor like follows:

您正在使用设计器处理事件。例如,您可以在构造函数中执行此操作,如下所示:

this.Load += delegate { IsFormLoaded = true; };
button1.Click += delegate { IsButton1Clicked = true; };

IMO it's more elegant :)

海事组织它更优雅:)

回答by atlaste

Funny question, seems to me like something you don't want to write over and over again. That's why I would rather go for a single generic component, than a hashset or something like that. Also, since form implementations are normally based on threads, I use a concurrent dictionary.

有趣的问题,在我看来,你不想一遍又一遍地写一些东西。这就是为什么我宁愿选择单个通用组件,而不是散列集或类似的东西。此外,由于表单实现通常基于线程,因此我使用并发字典。

This solution can be improved in a couple of different ways; most obviously making the handling more generic as well and lack of the 0-parameter handler. I kept it as simple as possible for clearance. Perhaps I'll probably post something more complete on my blog in a couple of days; if I do I'll share the info here.

可以通过几种不同的方式改进此解决方案;最明显的是使处理更加通用并且缺少 0 参数处理程序。为了通关,我尽可能地保持简单。也许几天后我可能会在我的博客上发布更完整的内容;如果我这样做,我会在这里分享信息。

My solution has 2 parts: (1) a generic hook class and (2) the implementation in the form. Currently the solution is lazy, e.g. I put event handlers at the end, not at the front of the queue. You should be able to fix this by using GetInvocationList or something similar.

我的解决方案有两个部分:(1)一个通用的钩子类和(2)表单中的实现。目前的解决方案是懒惰的,例如我将事件处理程序放在最后,而不是在队列的前面。您应该能够通过使用 GetInvocationList 或类似的东西来解决这个问题。

The generic hook class basically hooks events and keeps track if an event is called:

通用钩子类基本上钩子事件并跟踪事件是否被调用:

public class EventHooks
{
    private class EventHooksEquality : IEqualityComparer<Tuple<string, object>>
    {
        public bool Equals(Tuple<string, object> x, Tuple<string, object> y)
        {
            return x.Item1.Equals(y.Item1) && object.ReferenceEquals(x.Item2, y.Item2);
        }

        public int GetHashCode(Tuple<string, object> obj)
        {
            return obj.Item1.GetHashCode();
        }
    }

    private ConcurrentDictionary<Tuple<string, object>, bool> called =
        new ConcurrentDictionary<Tuple<string, object>, bool>(new EventHooksEquality());

    private abstract class BaseHookHandler
    {
        protected BaseHookHandler(object container, string eventName, EventHooks hooks)
        {
            this.hooks = hooks;
            this.container = container;
            this.eventName = eventName;
        }

        protected string eventName;
        protected object container;
        protected EventHooks hooks;
    }

    private class HookHandler<T1> : BaseHookHandler
    {
        public HookHandler(object container, string eventName, EventHooks hooks)
            : base(container, eventName, hooks)
        {
        }
        public void Handle(T1 t1)
        {
            hooks.called.TryAdd(new Tuple<string, object>(eventName, container), true);
        }
    }

    private class HookHandler<T1, T2> : BaseHookHandler
    {
        public HookHandler(object container, string eventName, EventHooks hooks)
            : base(container, eventName, hooks)
        {
        }
        public void Handle(T1 t1, T2 t2)
        {
            hooks.called.TryAdd(new Tuple<string, object>(eventName, container), true);
        }
    }
    // add more handlers here...

    public void HookAll(object obj)
    {
        foreach (var eventHandler in obj.GetType().GetEvents()) 
        {
            Hook(obj, eventHandler.Name);
        }
    }

    public void Hook(object obj, string eventHandler)
    {
        if (obj == null)
        {
            throw new Exception("You have to initialize the object before hooking events.");
        }

        // Create a handler with the right signature
        var field = obj.GetType().GetEvent(eventHandler);
        var delegateInvoke = field.EventHandlerType.GetMethod("Invoke");
        Type[] parameterTypes = delegateInvoke.GetParameters().Select((a) => (a.ParameterType)).ToArray();

        // Select the handler with the correct number of parameters
        var genericHandler = Type.GetType(GetType().FullName + "+HookHandler`" + parameterTypes.Length);
        var handlerType = genericHandler.MakeGenericType(parameterTypes);
        var handlerObject = Activator.CreateInstance(handlerType, obj, eventHandler, this);
        var handler = handlerType.GetMethod("Handle");

        // Create a delegate
        var del = Delegate.CreateDelegate(field.EventHandlerType, handlerObject, handler);

        // Add the handler to the event itself
        field.AddEventHandler(obj, del);
    }

    public bool IsCalled(object obj, string eventHandler)
    {
        return called.ContainsKey(new Tuple<string, object>(eventHandler, obj));
    }
}

Usage in a class can be done as follows (example):

在类中的使用可以按如下方式完成(示例):

   public Form1()
    {
        InitializeComponent();

        hooks.HookAll(this);
        // or something like: hooks.Hook(this, "Load");
        hooks.Hook(button1, "Click");

    }

    private EventHooks hooks = new EventHooks();

    private void Form1_Load(object sender, EventArgs e)
    {
    }

    private void button1_Click(object sender, EventArgs e)
    {
        this.textBox1.Text = 
            string.Format("Load: {0}\r\nClick: {1}\r\nButton click: {2}\r\n",
            hooks.IsCalled(this, "Load"),
            hooks.IsCalled(this, "Click"),
            hooks.IsCalled(button1, "Click"));
    }

回答by Dhawalk

Write your own Base Form(deriving from the Windows.Forms.Form), and override the event firing methods to capture if an event was fired or not. By having a base class, you will be able to reuse your event monitoring logic in all your forms.

编写您自己的基本表单(从 Windows.Forms.Form 派生),并覆盖事件触发方法以捕获事件是否被触发。通过拥有基类,您将能够在所有表单中重用事件监视逻辑。

Here's some example code that you can use. I have used only Loaded event here. You will have to do this for all the events you want to monitor. You can also use enum than using the constants. Hope this helps

这是您可以使用的一些示例代码。我在这里只使用了 Loaded 事件。您必须为要监视的所有事件执行此操作。您还可以使用枚举而不是使用常量。希望这可以帮助

        const string OnLoadFired = "OnLoadFired";
        const string OnShownFired = "OnShownFired";
        List<string> eventsFired = new List<string>();

        protected override void OnLoad(EventArgs e)
        {
            if(!eventsFired.Contains(OnLoadFired))
            {
                eventsFired.Add(OnLoadFired);
            }
            base.OnLoad(e);
        }

        public bool IsEventFired(string eventName)
        {
            return eventsFired.Contains(eventName);
        }

回答by paparazzo

Similar to answer from Dhawalk. I did not see that answer before I wrote this.

类似于 Dhawalk 的回答。在我写这篇文章之前我没有看到那个答案。

        private HashSet<string> events = new HashSet<string>();
        private void IsLoaded(object sender, RoutedEventArgs e)
        {
            // check
            System.Diagnostics.Debug.WriteLine(CheckEvents("IsLoaded", true).ToString());
            // add
            System.Diagnostics.Debug.WriteLine(CheckEvents("IsLoaded", false).ToString());
            // check
            System.Diagnostics.Debug.WriteLine(CheckEvents("IsLoaded", true).ToString());
        }

        private bool CheckEvents(string Event, bool CheckAdd)
        {
            // CheckAdd True to check
            // CheckAdd Fasle to add
            bool result = events.Contains(Event);
            if (!result && !CheckAdd) events.Add(Event);
            return result;
        }