text: You remember WinForms don’t you? WinForms applications are still around, in huge quantities. Some of us still need to maintain or rehabilitate WinForms applications, and testing events is particularly important when working with WinForms. The WinForms designer takes responsibility for wiring up many events for you, then discourages you from thinking too hard about what it did. Not only does it put the event wiring code in a semi-hidden
  Designer file, it also encloses the code it doesn’t want you touch in a region and adds a large comment explaining that you really should slowly back away before you hurt yourself.
  Even if you heed all of the warnings and stay out of that code, its still far too easy to add useless empty handlers from within the designer, or worse—accidentally unhook your events. Unit testing your handler implementations wont help, nothing in the internal implementation changes when a handler is wired (or unwired) from an event. You need something like the event tests I’ve been working on to make sure that the proper code is invoked when you perform an action on the GUI (for example, clicking a button).
  To build a system for inventorying events on WinForms controls, you should have a good idea how events work elsewhere in the .NET Framework. Here’s a short list of posts on this blog which should get you up to speed:
  - “Beyond the Event Horizon: Delegate Basics” — Explores the useful
  Delegate.GetInvocationListmethod.
  - “Beyond the Event Horizon: Event Basics” — Explains the relationship between Delegates and Events, and how the compiler implements simple events.
  - “Beyond the Event Horizon: Events You Don’t Own” — Shows how to use reflection to retrieve delegates for events declared on classes you can’t or won’t change.
  - “Beyond the Event Horizon: Event Complications” — Completes the toolset introduced in part 3 by handling inherited events and events of any delegate type.
  I’ve made the code associated with these articles available on GitHub. The code described in this article is a reimplementation of features available in a free, open source testing library called ApprovalTests, which you can download from SourceForge or NuGet and start using immediately. By using ApprovalTests, you can save yourself the bother of cut-and-paste, and the maintenance headache of keeping your own copy of the code. Need help getting started with ApprovalTests? Check out Llewellyn Falco’s fantastic series on YouTube and you will be up to speed in no time.
  So, will my event testing system work on
  WinForms? On the surface it seems like it will, but lets give it a try and see what happens.
  Start With A Failing Test
  First I’ll create a simple
  Form. I won’t be using the designer. Some of you might have never ventured into the “forbidden zone” inside the Designer file. I’ll implement the Form by hand, and this will give you your first bit of insight into how events work in WinForms.
  First I need to add a reference to
  System.Windows.Forms and import the namespace having the same name.
  using System.Windows.Forms; public class DemoForm : Form { }
  While I design, I’ll use
  WinFormsApprovals.Verify to get feedback as I work.
  [TestClass] public class WinFormsDemo { [TestMethod] public void VerifyDemoFormView() { WinFormsApprovals.Verify(new DemoForm()); } }
  This test will continue to fail until I approve it, so each time I run it I’ll see what
  DemoForm looks like. Now that I can see what I’m doing I can quickly add a few controls to the form. For example, here I add a
  Button.
  private Button button1; public DemoForm() { this.button1 = new Button(); this.button1.Text = "Click Me!"; this.Controls.Add(this.button1); }
  And I can see what this looks like in TortoiseIDiff:
  And here’s a
  CheckBox:
  private CheckBox checkBox1;); }
  The layout code is ugly, but it gets the job done.
  Finally, I’ll have a
  ListBox too:); this.listBox1 = new ListBox(); this.listBox1.Location = new Point( 10, this.button1.Location.Y + this.button1.Height + 10); this.listBox1.Size = new Size( this.Width - 40, this.Height - this.button1.Height - 40); this.Controls.Add(this.listBox1); }
  And here’s my final
  Form. Fantastic design if you ask me. I’ll apply a
  ClipboardReporterAttribute to the test method and approve the result. Doing this locks down the look and feel.
  Now I want to add another failing test to lock down the event handlers for the form.
  [TestMethod] public void VerifyDemoFormEvents() { EventUtility.VerifyEventCallbacks(new DemoForm()); }
  And here are the results:
  Event callbacks for DemoForm
  Throughout these posts I’ve been implying that this code base wont work with WinForms but we haven’t proved that yet. Before I can say that its not working, I need to wire up some events!
  public DemoForm() { // ... this.button1.Click += this.ButtonClick; this.checkBox1.CheckedChanged += this.HandleCheckedChanged; this.Load += this.HandleFormLoad; }
  I’ve wired up three events but none of them show up in the results. Right away I can see that there might be a problem with the
  Button and
  CheckBox, those events are wired up to child objects, and I’ve never tried to do anything other than get events off the top level object. However, the
  HandleFormLoad method is wired up to the
  Form.Load event, which is part of the top-level object and isn’t showing up either.
  Now I’ve got a TODO list:
  - Figure out why the handler attached to Load is missing.
  - Detect events wired up to child controls.
  WinForms Event Implementation
  In my last post, I thought I had discovered the end-all-be-all technique for finding events of any type, but the missing
  Load event proves me wrong. According to MSDN, Form.Load has this signature:
  public event EventHandler Load
  That doesn’t seem very exotic. When I debug my test and query the type in the Immediate window, I get the following output:
  typeof(DemoForm).GetEvents() {System.Reflection.EventInfo[91]} [0]: {System.EventHandler AutoSizeChanged} [1]: {System.EventHandler AutoValidateChanged} [2]: {System.ComponentModel.CancelEventHandler HelpButtonClicked} [3]: {System.EventHandler MaximizedBoundsChanged} [4]: {System.EventHandler MaximumSizeChanged} [5]: {System.EventHandler MarginChanged} [6]: {System.EventHandler MinimumSizeChanged} [7]: {System.EventHandler TabIndexChanged} [8]: {System.EventHandler TabStopChanged} [9]: {System.EventHandler Activated} [10]: {System.ComponentModel.CancelEventHandler Closing} [11]: {System.EventHandler Closed} [12]: {System.EventHandler Deactivate} [13]: {System.Windows.Forms.FormClosingEventHandler FormClosing} [14]: {System.Windows.Forms.FormClosedEventHandler FormClosed} [15]: {System.EventHandler Load} // Many more events...
  Maybe something is wrong with the way I’m building my type collection in
  GetEventCallbacks. I’ll use
  Extract Method to break out the type collection query so that I can test it in isolation.
  public static IEnumerable<EventCallback> GetEventCallbacks( this object value) { return value.GetEventsForTypes(GetEventTypes(value).ToArray()); } public static IEnumerable<Type> GetEventTypes(object value) { return GetType(value).GetEvents().Select(ei => ei.EventHandlerType).Distinct(); }
  This change doesn’t break any existing tests. I’ll add a test to see what happens when this method queries
  DemoForm.
  [TestMethod] public void GetEventTypeForDemoForm() { ApprovalTests.Approvals.VerifyAll( ReflectionUtility.GetEventTypes(new DemoForm()), string.Empty); }
  The results look and
  EventHandler, the delegate type backing
  Form.Load, is right there in slot 0.
  [0] = System.EventHandler [1] = System.ComponentModel.CancelEventHandler [2] = System.Windows.Forms.FormClosingEventHandler [3] = System.Windows.Forms.FormClosedEventHandler [4] = System.Windows.Forms.InputLanguageChangedEventHandler [5] = System.Windows.Forms.InputLanguageChangingEventHandler [6] = System.Windows.Forms.ScrollEventHandler [7] = System.Windows.Forms.ControlEventHandler [8] = System.Windows.Forms.DragEventHandler [9] = System.Windows.Forms.GiveFeedbackEventHandler [10] = System.Windows.Forms.HelpEventHandler [11] = System.Windows.Forms.InvalidateEventHandler [12] = System.Windows.Forms.PaintEventHandler [13] = System.Windows.Forms.QueryContinueDragEventHandler [14] = System.Windows.Forms.QueryAccessibilityHelpEventHandler [15] = System.Windows.Forms.KeyEventHandler [16] = System.Windows.Forms.KeyPressEventHandler [17] = System.Windows.Forms.LayoutEventHandler [18] = System.Windows.Forms.MouseEventHandler [19] = System.Windows.Forms.PreviewKeyDownEventHandler [20] = System.Windows.Forms.UICuesEventHandler
  The next logical problem could be that the
  GetEventsForTypes method is not finding any fields assignable to
  EventHandler on
  Form or any of its ancestors. I’ll write another test to focus in on that possibility.
  [TestMethod] public void GetEventsForDemoFormEventHandlers() { ApprovalTests.Approvals.VerifyAll( new DemoForm().GetEventsForTypes(typeof(EventHandler)), string.Empty); }
  ApprovalTests reports that the result set is empty. That’s a problem. Why isn’t it finding the field backing
  Form.Load? Is there a field backing
  Form.Load? My testing assumes that every event is implemented by the compiler, and as a result, every event should have a delegate backing the event, declared as a private field. What if WinForms uses custom add/remove methods instead of compiler implemented events?
  I can use ILSpy to figure out what’s going on. Sure enough, ILSpy shows a custom add/remove implementation.
  public event EventHandler Load { add { base.Events.AddHandler(Form.EVENT_LOAD, value); } remove { base.Events.RemoveHandler(Form.EVENT_LOAD, value); } }
  Instead of adding and removing delegates from a private instance field on
  Form, these add and remove methods make calls to a protected property called
  Events. ILSpy tells me that
  Events is an instance of
  EventHandlerList. I don’t know what that is yet, but before I try to figure it out I want to spend a little more time inside
  Form. The purpose of
  value is easy to understand, it is the delegate to add or remove, but what about
  Form.EVENT_LOAD?
  EVENT_LOAD refers to a private static read-only object, initialized to
  new object(). This argument it is just a reference to some unique chunk of memory on the managed heap, it can’t be changed, and every instance of
  Form has access to the same unique reference. I notice that there are many more static objects like this on
  Form. For example,
  Form has
  EVENT_MENUCOMPLETE,
  EVENT_MENUSTART,
  EVENT_RESIZEBEGIN, and so on. Presumably there is a static object which corresponds to each event implemented with custom add/remove methods similar to
  Form.Load.
  If I navigate to the
  Events property declaration I find it declared on
  System.ComponentModel.Component:
  protected EventHandlerList Events { get { if (this.events == null) { this.events = new EventHandlerList(this); } return this.events; } }
  The property lazily instantiates an
  EventHandlerList when needed, and that’s about it.
  EventHandlerList also lives in the
  System.ComponentModel namespace. Despite it’s name, it does not derive from
  List, nor does it implement any list or collection interfaces. I’ll look at
  AddHandler to see what it does when it receives the static object and handler delegate.
  public void AddHandler(object key, Delegate value) { EventHandlerList.ListEntry listEntry = this.Find(key); if (listEntry != null) { listEntry.handler = Delegate.Combine(listEntry.handler, value); return; } this.head = new EventHandlerList.ListEntry(key, value, this.head); }
  From this method’s point of view, the static object is called
  key and the delegate is called
  value. So,
  EventHandlerList is logically closer to a dictionary than a list. When
  AddHandler executes, the dictionary attempts to find an existing value with that key. When found, the new delegate is combined with the existing delegates, otherwise the method creates a new dictionary entry. The last line of the method might give some insight into how
  EventHandlerList stores its data, if I knew how
  EventHandlerList.ListEntry was implemented.
  Here is
  ListEntry‘s entire implementation:
  private sealed class ListEntry { internal EventHandlerList.ListEntry next; internal object key; internal Delegate handler; public ListEntry(object key, Delegate handler, EventHandlerList.ListEntry next) { this.next = next; this.key = key; this.handler = handler; } }
  In a typical .NET dictionary, each entry provides a key and a value.
  ListEntry provides these members, but also a reference to the next entry. So,
  EventHandlerList is a hybrid dictionary/linked-list.
  Missing Pieces
  After finding
  ListEntry I don’t need to look any further. Since
  WinForms has taken us deep into a rabbit hole, I’ll restate my goals:
  Given a Form to examine, make one call that will inventory the event handlers attached to the Form and each of the Form’s controls. Display the inventory where each invocation list is associated with the event it’s attached to, and each event is associated with the type it is declared on.
  Let’s compare how I solved each part of this problem in the
  Poco example with how I will need to solve it in the
  WinForms example.
  - Find Invocation List
  - Poco: Find the delegate field backing the event; call
  GetInvocationList
  - WinForms: Find the
  ListEntryinstance in
  Events; access the
  handlerfield and call
  GetInvocationList
  - Associate Invocation List with Event
  - Poco: Use the delegate field name.
  - WinForms: Use the name of the static object used as the
  ListEntrykey.
  - Associate Event with Object
  - Poco: Use the Type name.
  - WinForms: Use the
  Formtype name for
  FormEvents. Use the
  Controltype name for each child control.
  I think the biggest difference while constructing a query will be the way the invocation list is associated with an event name. With POCO events I could get both the invocation list and the name from the same delegate reference. By the time a
  Component stores an event delegate in a
  ListEntry the event name is lost and everything is called
  key. The CLR doesn’t care about the name because it checks the key with a reference comparison, it just needs the pointer.
  Besides the query, I’m going to need a lot of plumbing just to make the data structure queryable.
  ListEntry is private, nested and sealed. The compiler wont even acknowledge it’s existence:
  EventHandlerList.ListEntry entry; // Won't compile
  Error:
  Error 1 The type name 'ListEntry' does not exist in the type 'System.ComponentModel.EventHandlerList'
  And since
  EventHandlerList doesn’t implement
  IEnumerable or
  IEnumerable<T>, it doesn’t play nice with LINQ:
  EventHandlerList ehl = new EventHandlerList(); var q = from e in ehl select e; // Wont compile
  Error:
  Error 1 Could not find an implementation of the query pattern for source type 'System.ComponentModel.EventHandlerList'. 'Select' not found.
  So, before I can write my queries, I’ll need to get under there and do some plumbing.
  Relationship With EventApprovals
  This article has been a bit of a tease. While I hope I’ve provided some useful information, I haven’t really produced any solutions. The relationship with EventApprovals is that all of these problems are already solved in ApprovalTests! When you call
  ApprovalTests.Events.EventApprovals.VerifyEvents, WinForms events are supported and will appear in your inventory.
  Up Next
  In this article’s next installment: “Beyond the Event Horizon: WinForms Plumbing”, I will use what I’ve learned about WinForms to build up the plumbing pieces necessary to make a usable wrapper for
  ListEntry and an enumerable adapter for
  EventHandlerList. With those pieces of plumbing out of the way then I can return to my TODO list, find the missing
  Form.Load event, and figure out how I want to capture the events declared on child controls.