Part II: Web & Window Form Unification: Synchronous And Asynchronous Event Handling For Controls Created At Runtime

This is the second part of a multipart article on unifying web and window form application development. This part demonstrates synchronous and asynchronous event handling of GUI control events, abstracting the implementation of web/window forms to be technology independant.

Introduction

This is the second part of a multipart article on unifying web and Windows form application development.
In the first part, I demonstrated a mechanism for unifying Web Form and Windows Form controls.
In Part II, I will demonstrate an interface for events that abstracts web and window form event differences
and synchronous/asynchronous event consumers.

A programmer typically implements GUI control event handlers as methods in the web or window form class that
contains the control, or possibly as a method in a class derived from a GUI control. A similar mechanism can
be used even for runtime created controls. However, this requires that the form or page be created at the
time of implementation so that the appropriate event handlers can be implemented as methods to the form/page.

In my dynamic GUI generation tool, the form/page is dynamically instantiated (or an equivalent
generic template). This requires an interface for associating the event handlers with the GUI control
event, because the event handlers cannot be associated with a dynamically created form/page.

Granted, the Web Forms version is not quite as dynamic, as it utilizes an existing label on the main
form to create child controls, but the concept is the same:

DynWebForm mainForm=new DynWebForm();
mainForm.Init(Label1);

To support event in a dynamic form/page framework, events consumers are declared as static methods and are
registered into an event collection with a key/value pair where the key is a unique textual name and the
value is the System.EventHandler delegate. A control is associated with a particular event by name,
therefore allowing control-event associations to be handled in the resource script.

Benefits

This has the benefit of enforcing a design technique that I feel is better than the classical method of
handling the GUI control event in the parent form or the sub-classed control. For example, I've seen
many cases where complex functionality was included in the event handler (pseudo code follows

In many large applications, I have found programmers performing a copy/paste for event handlers that
perform similar, if not the same, functionality. This is redundant and makes it harder to modify and
maintain the application. Instead, I prefer that all event handlers be separated out from the strict
GUI implementation. This also creates a clean separation between the presentation and
the "business logic", or functionality, of the application. For example, I think it is better
design to implement the above example as:

This might seem like overkill for simple events, especially those that end up merely changing the state
of some other GUI element, and I agree. However, I find that it is a good idea to do things consistently
as to create a good habit.

If implemented correctly, the event handler can be invoked in other ways as well, besides by GUI control
events. This improves the modularity of the code. Also, if the framework (as I will illustrate mine does)
supports asynchronous events (as does C#), the programmer can choose whether the event is handled in the
main application thread or as a worker thread.

A side effect to this style of event management is that event consumers are usually declared as static
methods. This is actually preferable, especially in Web Forms applications, which are stateless, and an
object instance is not preserved between page loads.

The Event Collection Class

The event collection class is a thin wrapper around the SortedList class:

The SortedList class would be sufficient by itself, but I prefer to create a wrapper around
generic containers so that I can add additional functionality later. Also, I could have derived the
EventManager class from SortedList. I do not usually like doing this because I
want to restrict the application?s access to the container. This way, the exception handling is reduced
if the wrapper class is more involved in the management of the data.

Invoking The Event

The event invocation is handled by the base class of all the dynamic controls, DynControl:

The InvokeEvent method determines whether the event should be invoked synchronously or
asynchronously (as discussed below). What is elegant about this is that the same method is used
regardless of whether the event is triggered by a Web Form or a Windows Form. The implementation
abstracts the specifics of both technologies so that the application doesn?t have to concern itself with
this issue. (Of course, there are complexities to this that we will get into in later parts).

Tying Events In To The Control Creation Script

In Part I, I introduced an approach that creates GUI?s essentially from a "resource script" (albeit hard-coded
for now, but that will change in Part IV, when database interfaces is introduced). As part of the form/page
initialization, it is possible to associate event consumers with the desired GUI control at the time that
the page/form is loaded. For example, for each dynamic control instantiated, an event could be created as
follows (more pseudo code):

This implementation tightly couples the consumer with the control, and we violate the design rule I
stated above, which is to attempt to disassociate the business logic of the application from the GUI
presentation. Instead, the EventManager class is used, as described above. Using the
EventManager mechanism, event consumers can be referenced by name, not by function. This
decouples the event generator from the consumer. Event consumers are registered using:

EventManager.EventCollection.Add("ClearForm",
new System.EventHandler(AppEvents.ClearForm));

And the event consumer is coupled to the control itself as part of the ControlInfo that is
passed to the dynamic control during creation. For example, the ControlInfo structure is
initialized as follows:

Web Forms Events vs. Window Forms Events

In Windows Forms, the Click event is a member of the base class, System.Windows.Forms.Control for
all controls. Furthermore it takes the same parameters regardless of the control. This allows us to
implement the hander in the DynWindowControl base class. Unfortunately, this is not true
for web controls, the base class for web controls has no Click event, and furthermore,
different controls produce different parameters. This means that the event handlers must be coded
specifically for each web control. While annoying, once the work is done the programmer performing the
application coding can ignore the complexities of web events. For example, the ImageButton web control
requires its own unique event consumer:

Note however the loss of certain information, for example, X/Y coordinate information. This issue will be
addressed in the Part III: Interfacing To And Abstracting Control Data.

Conclusion

This article builds on the framework described in Part I, which demonstrated unifying Web Form and Window Form
control instantiation and rendering. Part II demonstrates how to abstract Web Form and Windows Form
events so that an application can be written without concern to the underlying technology. The issues of
accessing control properties has not been addressed in this article (therefore, no pretty pictures at
the beginning of the article either!). Part III will discuss this issue and introduce the concept
of a DataContainer for managing the interface between the business logic event handlers
and the presentation system.

The code distributed with this article demonstrates that the event handlers actually work. A message is
displayed in the Windows Forms application, and the programmer can set a breakpoint in the Web Forms
application to verify that clicking on the pencil image button actually invokes the event.

The Zip File

The zip file contains the Windows Forms demo and DynForm library, which are installed starting in
the projects.net directory. The Web Forms project, AspNetForm, unzips into the aspNetForm directory.
I?d unzip everything into a temp directory, preserving path, and then copy the code into the appropriate
directories of your choice.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.