October 02, 2006

Custom Events, Delegates, and More!

Creating custom events allow us to tailor events to be the most descriptive for the given tasks. It is common practice to also add in additional information to a custom event to provide additional information. In this post I will show you how to create a custom event handler to broadcast Database Errors throughout an application. This example allows you to have data processing methods that go through a large number of operations but internally handle errors, raise the event, and then keep processing.

This example is broken into the following parts:

  • Creating a custom EventArgs class
  • Declaring a delegate to handle your custom event
  • Declaring and raising a public event for consumption
  • Subscribing to the event from another process


Creating a custom EventArgs Class

First we need to create a custom class to handle the information for our event, we will want to have this class derive from the EventArgs class. Below is an example of a DatabaseErrorEventArgs class that I have created, below the code sample is a summary of what is in the code.

    public class DatabaseErrorEventArgs :EventArgs
    #region Private Data Members
    System.Data.SqlClient.SqlException mException;
    string mSectionDetail;
    bool mIsCritical;
    #region Constructor
    public DatabaseErrorEventArgs(System.Data.SqlClient.SqlException ex, string section, bool critical)
        this.mException = ex;
        this.mSectionDetail = section;
        this.mIsCritical = critical;
    #region Public Properties
    public System.Data.SqlClient.SqlException DatabaseError
        get { return mException; }
    public string ErrorSection
        get { return mSectionDetail; }
    public bool IsCritical
        get { return mIsCritical; }

If you notice in the constructor I require that all three parameters be sent, I also provided three public properties to expose the values of the internal members. In addition to the methods I have listed here you might also want to override the "ToString" method of the EventArgs class to provide custom text when calling "ToString".

Declaring a delegate to handle your custom event

I think everyone at times has been confused about delegates and what they are, I have found the following "description" very helpful. "A delegate serves as a special event handler, identifying the signature of our event. This ensures that ALL handlers of the event will have all desired event information." With this in mind for our DatabaseErrorEvent we want to ensure that the listener to the event knows the following: Who created the error and what the details were. Therefore we will have 2 parameters in our delegate. (Sender and e to follow the event standards). A delegate is declared as a void method with no body and the delegate keyword, an example of our delegate is below.

public delegate void DatabaseErrorEvent(object sender, DatabaseErrorEventArgs e);

This creates a special event handler so now we can raise events elsewhere in our application and state that the event is a DatabaseErrorEvent. By doing this we will ensure that the DatabaseErrorEventArgs is provided. Since the delegate and the EventArgs class are so closely related I typically include them both in the same .cs file in my solution as it makes it much easier to find the declaration later.

Declaring and raising a public event for consumption

Now that we have an EventArgs class and a delegate it is time to create and raise an event from our code for users to subscribe to. First we need to declare the event, this event declaration must be within a class and should be formed like the following.

public event DatabaseErrorEvent CriticalFailure;

This creates an event called CriticalFailure which is of the type DatabaseErrorEvent, which when raised will provide information regarding the sender and a populated instance of DatabaseErrorEventArgs. To raise this event it is farily simple, you will want to create a protected virtual void method to accomplish this. The reason for using "protected virtual" instead of private or internal is to ensure that if the class was ever extended/inheritied in the future that the new implementation could overrride and call the method.

This method to raise the event is traditionally called an OnError event, therefore for ease of maintaining your code you should name it consistently. In the case of our example the event is CriticialFailure, therefore the method should be OnCriticalFailure. Below you will find the code for the OnCriticalFailure method, I will describe a few things below the code sample.

protected virtual void OnCriticalFailure(DatabaseErrorEventArgs e)
    if (this.CriticalFailure != null)
        this.CriticalFailure(this, e);

In this statement you will notice that we check to ensure that CriticalError is not equal to null. This simply ensures that we have at least one subscriber to the method. If we have no subscribers it is not necessary to raise the event. In your code when you want to raise a "CriticalError" you simply call OnCriticalError passing it a valid DatabaseErrorEventArgs instance. You can view this code in the linked file below.

Subscribing to the event from another process

Now that you have the EventArgs class created, the delegate created and all of the methods in place to raise the event your final step is to subscribe and respond to the event from elsewhere in your code. This part is fairly simple. Simply instantiate your worker class, add the handler which points to the method that will respond to the raised event. Below is an example. (Also included in the code sample).

private void btnGo_Click(object sender, EventArgs e)
    //Clear results
    lblResult.Text = "";
    //instantiate the worker
    DemonstrationWorker oWorker = new DemonstrationWorker();
    //Subscribe to the criticial error event
    oWorker.CriticalFailure += new DatabaseErrorEvent(oWorker_CriticalFailure);
    //Call it's do work method
    //Mark as done
    lblResult.Text = "Finished";
/// Responds to the raising of the critical failure notice
void oWorker_CriticalFailure(object sender, DatabaseErrorEventArgs e)
    //Show it was done
    MessageBox.Show("Critical Failure Indicated!! \n" + e.DatabaseError.Message);

Note the line that starts with "oWorker.CriticalFailure +=" this is the line that allows your calling class to listen for the CriticalFailureEvent. Notice the handler that we are adding is declared as a new DatabaseErrorEvent which is what our delegate was. The value inside the ()'s is the name of the method to call when the event is raised.

If you run the included sample application when you click on the "Perform Demo" button you should notice a 2 second delay, then you should get a message box, then after about 6 more seconds you will see the text "Finished" in the display label. This was a fairly simple example of how you can create and generate your own events. If there are any questions or if you have ideas for other topics please let me know.

tags: Tutorials, Windows Applications, ASP.NET, .NET 2.0
comments powered by Disqus

Content provided in this blog is provided "AS-IS" and the information should be used at your own discretion.  The thoughts and opinions expressed are the personal thoughts of Mitchel Sellers and do not reflect the opinions of his employer.

Content Copyright

Content in this blog is copyright protected.  Re-publishing on other websites is allowed as long as proper credit and backlink to the article is provided.  Any other re-publishing or distribution of this content is prohibited without written permission from Mitchel Sellers.