Separating Application Logic and Data Presentation layers

I'm a big advocate of separating an application's logic from it's user interface.  By keeping the logic separate from the data presentation layer (UI), it becomes easy to swap out either component with minimal impact on the other.  In addition to ease of replacing components, keeping the user interface separate from the application logic avoids blocking the UI during expensive operations.

Today, I'm going to revisit the .NET Compact Framework WebCrawler sample from Visual Studio 2005 and show how it uses event handlers to allow the application logic (Crawler class) to communicate with the user interface.  The source code for the WebCrawler sample can be downloaded from here.

Simple Status Notification - EventHandler
For simple notifications requiring no data, such as the CrawlFinishedEvent in the WebCrawler sample, an event handler is defined in the application logic class.

public event EventHandler CrawlFinishedEvent;

When the application logic wishes to inform clients that the event has occurred, it checks to see if there are any registered event handlers and, if so, sends the notification.

if (null != CrawlFinishedEvent){    CrawlFinishedEvent(this, EventArgs.Empty);}

The UI class (MainForm in the WebCrawler) registers for the event.

this.crawler.CrawlFinishedEvent += new EventHandler(HandleCrawlFinishedEvent);

The form implements a method to handle the event.

/// <summary>/// Process CrawlFinished events/// </summary>private void HandleCrawlFinishedEvent(object sender, EventArgs e){    // update the user interface as appropriate}

Sending Data In The Notification - Creating a Custom EventHandler
If the notification requires some data data, such as the CurrentPageEvent  in the WebCrawler sample, a custom event handler delegate will need to be defined.

public delegate void CurrentPageEventHandler(object sender, CurrentPageEventArgs e);public event CurrentPageEventHandler CurrentPageEvent;

Notice the CurrentPageEventArgs argument -- this is where the custom data is placed.  In the WebCrawler sample, the CurerntPageEventArgs is defined as

/// <summary>/// Class providing the current page address to the CurrentPageEvent handler/// </summary>public class CurrentPageEventArgs : EventArgs{    private string pageAddressValue;    /// <summary>    /// The address of the current page(ex: https://www.microsoft.com)    /// </summary>    public string PageAddress    {        get        {            return this.pageAddressValue;        }    }    /// <summary>    /// Constructor    /// </summary>    /// <param name="page">    /// The address of the current page    /// </param>    public CurrentPageEventArgs(string page)    {        this.pageAddressValue = page;    }}

As with the above simple status notification example, when the application logic wishes to inform clients that the event occurred, it checks registrations and sends the notification, passing the data in the event arguments.

if (CurrentPageEvent != null){    CurrentPageEvent(this,  new CurrentPageEventArgs(str));}

Registering for the custom event is similar to the above simple notification example.

this.crawler.CurrentPageEvent += new Crawler.CurrentPageEventHandler(HandleCurrentPageEvent);

The implementation of the event handler method needs to match the custom event handler delegate.

/// <summary>/// Process CurrentPage events/// </summary>private void HandleCurrentPageEvent(object sender, CurrentPageEventArgs e){    // update the user interface as appropriate}

By building and running the WebCrawler sample under the Visual Studio 2005 debugger, you can watch the event notifications and how the sample handles updating user interface elements in a multi-threaded application.

Enjoy!
-- DK

Disclaimer(s):
This posting is provided "AS IS" with no warranties, and confers no rights.