I'm trying to figure out a way to have my WinForms application log every button-click to a file. So far, the best solution I've found (from [Log all button clicks in Win Forms app](https://stackoverflow.com/questions/17949390/log-all-button-clicks-in-win-forms-app)) is something like:

```
public class ButtonLogger
{
    public static void AttachButtonLogging(ControlCollection controls)
    {
        foreach (var control in controls.Cast<Control>())
        {
            if (control is Button)
            {
                Button button = (Button)control;
                button.Click += LogButtonClick;
            }
            else
            {
                AttachButtonLogging(control.Controls);
            }
        }
    }

    private static void LogButtonClick(object sender, EventArgs eventArgs)
    {
        Button button = sender as Button;
        WriteLog("Click: " + button.Parent.Name.ToString() + "." + button.Name.ToString() + " (\"" + button.Text + "\")");
    }

    private static void WriteLog(string message)
    {
        //...
    }
}

```

Then at the end of each form's constructor:

```
ButtonLogger.AttachButtonLogging(this.Controls);

```

While this is a great approach, it suffers from 3 major drawbacks, all due to the fact that the log events will always occur after the "real" events (created by the Designer):

1) If the button click opens a modal dialog, clicks within that dialog will be logged before the parent's click (aka logs appear out-of-order). This is because the parent's click will only be logged once the modal dialog is closed, and thus after clicks within that dialog.

2) Similarly, if some action within that modal dialog causes the application to crash, the click that opened it will never be logged, making it appear as though the crash occurred in the parent.

3) If the button click closes the current dialog, button.Parent will be null (since the event that logs it will be fired *after* the dialog has already been closed by the "first" event). Thus, we can't log the name of the form from which the "close" click came.

I've been racking my brain for a way to reverse the order (so log-events get fired before "real" events), but can't come up with anything **that doesn't preclude using the Designer**. The issue is that the Designer both creates & assigns events within InitializeComponents(), which we can't edit.

Thoughts on possible (unsuccessful) solutions:

* Call AttachButtonLogging() from something that the Designer puts between button creation and adding events. However, the only thing there is a call to SuspendLayout(), which isn't virtual and thus can't be overridden (and buttons haven't yet been added to the ControlCollection at that point).
* Have AttachButtonLogging() remove each button's existing events, add the log event, then re-add originals. However, you can't enumerate a class's events from outside that class (i.e. AttachbuttonLogging can't enumerate a button's events).

It seems like something like this should be possible with some outside-the-box thinking, but I'm fresh out of ideas. Note: the goal is to log the clicks **in a way that's not cumbersome when building new dialogs** - similarly to the solution above, but without the three mentioned pitfalls.