Publish a Custom Event
Introduction
When I was new to object-oriented programming I tended to steer clear of adding custom events to my classes. Methods and properties were easy to grasp and setup and I just really had not come to understand how useful events were in order to be motivated to learn how to create them. But for those of you that have found this article I can assure you they are a very useful tool that can make things much simpler for you. After all, object-oriented programming is event-driven. Follow me in this article to learn how you can create your own custom event.
Why would you want to create a custom event? Several reasons really. Let me give you a couple examples. Let’s say you’ve created a user control in your latest ASP.NET application. In that user control you’ve added a control that causes a postback – let’s say a button to keep things simple. And in this case you want the page that consumes your user control to have the option of performing some task whenever the button in your user control is pressed. Well by default the page would not be able to access the button control in order to subscribe to its Click event. So what I like to do is commonly referred to as “bubbling up” the event. I do this by adding a new event to my user control. You can call this event whatever you like. In this instance I will call it “Submit”. Because the click event of the button uses the basic “EventHandler” we won’t need to create a delegate. We only need to add one line of code to our user control’s code-behind to declare this event.
public event EventHandler Submit;
Now in order to “bubble up” the event we need to create an event handler for the button’s click event and then raise our Submit event. If you’re in design view for your user control you can double-click your button to add an event handler to your code behind. If you’re developing in C# then you’ll need to test the event to determine if any handlers have subscribed to it. In VB you can simply use the Raisevent keyword.
protected void Button1_Click(object sender, EventArgs e)
{
if (Submit != null)
Submit(this, e);
}
Notice that when I raised the Submit event I didn’t pass the sender received through the parameters. That’s because that sender was a reference to the button. But in this case I want to pass a reference to the user control which is in fact the publisher of the Submit event. With this in place the consuming page can now subscribe to the event and act whenever the button is pressed.
Another good reason to create a custom event is to be able to collect information from the subscriber at a specific time. Let’s say you’ve created a user control which has a databound control declared with a datasource. This particular datasource has one or more parameters in it whose values you want to obtain from the consuming page. Well again the best time to set the values of the parameters is in the Selecting event of the datasource. But the datasource is not public in scope by default and therefore not accessible by the page. So we’re going to create our own custom event that we can raise to collect the values we need for the parameters. Just to keep things simple I am going to setup the select statement in the datasource to be selecting against a table which contains a list of contacts. The select statement will pull all contacts in a specific state. Here is how the datasource will be declared in the user control.
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString='<%$ ConnectionStrings:MyConnection %>' OnSelecting="SqlDataSource1_Selecting" SelectCommand="SELECT FirstName, LastName FROM Contacts WHERE State = @State" SelectCommandType="Text">
<SelectParameters>
<asp:Parameter Name="State" Size="2" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
Now before I going any further with the datasource I want to setup all the necessary types for the custom event. We need to write our own class to pass through the event. Best practices state that our class will inherit from the System.EventArgs class. Because I am going to name the event “Selecting” I will call this new class SelectingEventArgs. You can call it whatever you want but this naming convention is very easy to understand. This class will expose one property called “State” which allows the consuming page to specify the state to filter on.
public class SelectingEventArgs : EventArgs
{
string _State;
public string State
{
get { return _State; }
set { _State = value; }
}
}
The next step is we need to create a delegate for our event. For some reason the concept of a delegate is what really stumped me in the beginning and was the real block for me in understanding events. Simply put a delegate holds a pointer to a method. The method must have the same signature that is laid out by the delegate. So when the event is raised the delegate plays a key role in calling the method that you setup to handle an event. You can declare your delegate inside your class but that is not necessary as it is its own type. Only one line of code is needed.
public delegate void SelectingEventHandler(object sender, SelectingEventArgs e);
Note a few things. First the delegate states that the method should not return a value. It also states that the method must accept two parameters. The first is an object type and the second is an instance of the class we just declared “SelectingEventArgs.” Also note the naming convention I used to name the delegate. It's very clear that it is a delegate and it's matched up with the SelectingEventArgs class. With our class and delegate in place we can declare our event in our user control. Again a very simple declaration - Just one line of code.
public event SelectingEventHandler Selecting;
The last three steps I took you through are actually all you need to do to create a custom event. Your class that extends EventArgs, your delegate and the event declaration in your class. But getting back to our example let me show you how it can be used. Our datasource publishes its own Selecting event. In the code-behind of our user control we will create an event handler for this event.
protected void SqlDataSource1_Selecting(object sender, SqlDataSourceSelectingEventArgs e)
{
SelectingEventArgs args = new SelectingEventArgs();
if (Selecting != null)
{
Selecting(this, args);
}
e.Command.Parameters["@State"].Value = args.State;
}
Our consuming page would then subscribe to the event by either declaring it in the markup as such:
<uc:UserControl ID="UserControl1" runat="server" OnSelecting="UserControl1_Selecting" />
Another option is in the code-behind preferably the Init event of the page:
protected void Page_Init(object sender, EventArgs e)
{
UserControl1.Selecting += new SelectingEventHandler(UserControl1_Selecting);
}
Then below is an example of implementing an event handler for this:
protected void UserControl1_Selecting(object sender, SelectingEventArgs e)
{
}
Notice my event handler matches the signature of the delegate.
Summary
That’s it! Now what we have in place is a user control which publishes an event that allows the consumer to take a strongly typed set of parameters and set their values at precisely the right time. Enjoy!