Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Refactoring Hooking and Unhooking Events TIP

0.00/5 (No votes)
4 Jan 2012LGPL32 min read 13.2K  
Refactoring Hooking and Unhooking Events TIP

I was fixing a bug w.r.t. event handling. So as part of this, there were couple of forms (classes basically) which were trying to hook to a KeyDown event and unhooking upon disposed. Basically the requirement is, for every customized control in the forms/panel, this keydown event should be hooked. So no matter which ever control (child/parent) has the focus, keydown event has to get fired. So as part of this implementation, the code goes like this:

C#
Hooking events:
public void HookEvents()
{
    IEnumerable < Controls > allControls =
            CollectUIControlsHelper.Instance.CollectAllControlsDeep(this);

    foreach (Control ctrl in allControls)
    {
        ctrl.KeyDown += new KeyEventHandler(OnControlKeyDownHandler);
    }
}

UnHooking events (Part of Dispose call):
public void UnHookEvents()
{
    IEnumerable < Controls > allControls =
           CollectUIControlsHelper.Instance.CollectAllControlsDeep(this);

    foreach (Control ctrl in allControls)
    {
        ctrl.KeyDown -= new KeyEventHandler(OnControlKeyDownHandler);
    }
}

As you can see from the above code, it's pretty clear that the first method is just collecting all the controls from parent to child from the current form/panel/control via a method CollectAllControlsDeel(this). And does the opposite in UnhookEvents. Do note that these methods are called in any fashion by the usage code. Hence, every call has to fetch all the child controls.

Yes, I do agree that this code is nothing great. But the annoying thing or the primary concern for me was to see this code getting repetitive in many forms or classes across my application.

So I wanted to make this above code perhaps more common so that any form which wishes to hook for Keydown events can just reuse this code. As part of that effort, I came up with this simple solution as shown in the below code:

C#
class KeyDownEventsHelper
{
    private static readonly KeyDownEventsHelper m_Instance =
             new KeyDownEventsHelper();

    public static KeyDownEventsHelper Instance
                   { get { return m_Instance; } }

    private KeyDownEventsHelper() { }
    static KeyDownEventsHelper() { }

    public void HookEvents(Control control,
             Action<object,KeyEventArgs> eventHandler)
    {
        IEnumerable < Control > allControls =
          CollectUIControlsHelper.Instance.CollectAllControlsDeep(control);

        foreach (Control ctrl in allControls)
        {
            ctrl.KeyDown += new KeyEventHandler(eventHandler);
        }
    }

    public void UnHookEvents(Control control,
            Action<object, KeyEventArgs> eventHandler)
    {
        IEnumerable < Control > allControls =
          CollectUIControlsHelper.Instance.CollectAllControlsDeep(control);

        foreach (Control ctrl in allControls)
        {
            ctrl.KeyDown -= new KeyEventHandler(eventHandler);
        }
    }
}

As you can see from the above code, it is a singleton class which publishes 2 methods for hooking and unhooking. So as part of these methods, I have provided a delegate for the eventhandler to invoke upon any events generated. So each class can provide its own even handlers for hooking.

Now, I am feeling a bit relaxed as I could reduce around 8 lines of code getting repeated over in many different forms/classes couple of times. So as of now, I could find 4 classes/forms which are repeating this above code, thus I could save around 32 lines altogether.

I do agree that there is still a lot of room for improvement. However, at the moment, I cannot foresee those improvements. It would be kind and great of you as a reader to suggest those improvements.

My next concentration would be to refactor the event handlers for KeyDown so that I can minimize the implementation code. Maybe I will add a base class to all of those classes which have a virtual method having common code and in the derived, I invoke first base and then implement a little more code.

Thanks and happy coding! :)

Filed under: C#, CodeProject, Dotnet
Tagged: .NET, bing, blog, blogger, C#, codeproject, Dotnet, google, tips

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)