3

次のようにイベントが発生したかどうかを追跡しています。

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

しかし、多くのイベントでこれを行うのはエレガントではないため、次のようにイベントが発生したかどうかを確認できるソリューションが必要です。

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

4 に答える 4

5

デザイナーを使用してイベントを処理しています。たとえば、次のようにコンストラクターで実行できます。

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

IMOそれはよりエレガントです:)

于 2013-01-08T14:24:19.070 に答える
1

おかしな質問ですが、何度も何度も書きたくないもののように思えます。そのため、ハッシュセットなどよりも、単一の汎用コンポーネントを使用したいと考えています。また、フォームの実装は通常スレッドに基づいているため、並行辞書を使用します。

このソリューションは、いくつかの異なる方法で改善できます。最も明らかに、処理もより一般的になり、0 パラメーター ハンドラーがなくなります。クリアランスのためにできるだけシンプルにしました。おそらく、2、3 日以内に、より完全なものをブログに投稿する予定です。もしそうなら、ここで情報を共有します。

私のソリューションには、(1) 一般的なフック クラスと (2) フォーム内の実装の 2 つの部分があります。現在、解決策は怠惰です。たとえば、イベント ハンドラをキューの先頭ではなく最後に配置しています。GetInvocationList または同様のものを使用して、これを修正できるはずです。

ジェネリック フック クラスは、基本的にイベントをフックし、イベントが呼び出されたかどうかを追跡します。

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

クラスでの使用は次のように行うことができます (例):

   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"));
    }
于 2013-01-08T15:31:08.427 に答える
0

独自のベース フォーム (Windows.Forms.Form から派生) を記述し、イベント発生メソッドをオーバーライドして、イベントが発生したかどうかをキャプチャします。基本クラスを持つことで、すべてのフォームでイベント監視ロジックを再利用できます。

使用できるコード例を次に示します。ここでは 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);
        }
于 2013-01-08T14:35:18.103 に答える
0

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;
        }
于 2013-01-08T15:12:07.980 に答える