February 7, 2012  
  You are here:  Blog

QTCommunicationSimplified50.gif


Try Radicomm's Quicktalk, the first enterprise-class Push-To-Talk application for your Motorola/Symbol rugged devices, in your distribution center for free.

Click here to enter the 21st Century.


C# Multicast Delegates - A Practical Example
 
Location: BlogsNetSplore's Blog    
Posted by: Joe Rattz 11/23/2006 4:04:44 AM

The C# language has a feature known as the multicast delegate.  Any delegate that has a void return type, is a multicast delegate.  A multicast delegate can be assigned and invoke multiple methods.

You may have seen hints of this in your code.  For example, if you are doing ASP.NET development and have ever looked at a page's InitializeComponent() method, you may have noticed a statement like this:

this.SearchButton.Click += new System.EventHandler(this.SearchButton_Click);

Notice the += in that statement.  That is a clue.  You could add another event handler if you wanted, and it would get called as well.  For example, let's say you wanted to also call a method named NotifyStatistics every time the Search button was clicked.  Then your code could be:

this.SearchButton.Click += new System.EventHandler(this.SearchButton_Click);
this.SearchButton.Click += new System.EventHandler(this.NotifyStatistics);

Every time the user clicks the Search button, first SearchButton_Click() is called, followed by NotifyStatistics().  The event handlers are called in the order they are added.  Likewise, using -=, an event handler can be removed.

Now, you may be asking, why not just add whatever code is in the NotifyStatistics method to the SearchButton_Click method?

 

My Problem - User Control Interdependence

So, it should come as no surprise that I had a problem for which I found multicast delegates to be a good solution.

I was working on a site where I wanted an organization to be able to have an announcement on their page.  I wanted this solution to be somewhat modular, so I wanted the UI code contained in an ASP.NET user control, that way I could use it for this purpose, as well as throw it on some other page if I had some other need for it in the future.  I call this user control the announcement viewer control.  Additionally, I needed the ability for a privileged user to be able to edit the announcement.  And, I wanted this functionality to be in a separate ASP.NET user control.  I wanted the user controls separate because the announcement editor user control may need to be on a different page than the announcement viewer control.  So far, so good.

The problem occurred when I put the announcement viewer and announcement editor on the same page.  When the privileged user edited the announcment and clicked the button to save, the page posted back to the server.  On the server, both the announcement editor and annoucement viewer called their Page_Load methods, and the viewer loaded the current announcement from the database.  Mind you, the user just changed the announcement and clicked the save button, but it hasn't gotten saved yet, because the method mapped to the save button hasn't been called yet.  Then, the save method that is mapped to the save button is called, and the modified announcement is persisted to the database.  However, the announcement viewer control has already loaded the announcement, so when the page renders in the browser, the announcement is correct in the announcement editor, but is the previous version in the announcement viewer control.  To the user, this is unsettling.  If the user refreshes the page, the correct version of the announcement will then get loaded into the announcement viewer control, and all is well.  But, this is an unacceptable situation that will make the user question that the announcement change was really saved.

How do you solve this problem?  I didn't want any direct connection between the announcement editor and announcement viewer because they wouldn't always be on the same page, and in some circumstances, may be used totally independently.  What to do?

 

My Solution - Multicast Delegates

In my situation, the only entity that I wanted to have any knowledge (code) that these two controls had a relationship was the page that they were on.  The page knows that it has both an announcement viewer and an announcement editor control.  So, it was the page that I wanted handling the coordination between the two controls.

What I came up with was the idea that someone, my page in this case, could register an event handling method with the announcement editor control.  Using the announcement editor's save button's multicast delegate for the click event, the registered event handling method would also get called when the announcement editor's save button was clicked, in addition to the editor's own method to actually persist the announcement to the database.

This allows the page to register a method with the announcement editor, and when the user clicks the save button, the page's method gets called.  The only other issue, was adding a refresh method to the announcement viewer control, which was insignificant.

So, the flow is that the user clicks the editor's save button, the button's save method is called, persisting the announcement to the database.  Next, the page's registered method is called, and that method calls the viewer's refresh method, which loads the just saved announcement back into the viewer.

This solution gives me the coordination between the two controls, without making either of them dependent on the other.  Multicast delegates have saved my day!

 

The Code

In my announcement editor module, I have added the following public method:

public void RegisterForSaveNotification(System.EventHandler eventHandler)
{
    this.SaveAnnouncementButton.Click += eventHandler;
}

In my announcement viewer module, I have added the following public method:

public void RefreshAnnouncement()
{
    // My code to load the announcement from the database goes here.
    announcementContent.InnerHtml =
        Announcements.GetAnnouncement(EntityType.Text, EntityId.Text, Int32.Parse(Sequence.Text));
}

And, to tie it all together, here is the code I have added to the page that they are both on:

In Page_Load, I have added the following call to RegisterForSaveNotification():

RegisterForSaveNotification();

if (!Page.IsPostBack)
{
    ...
}

I show the call in context of the check for postback because the event handler must be registered for gets and posts.  I would prefer to make the call in InitializeComponent(), but Visual Studio keeps deleting it when I put it there.

private void RegisterForSaveNotification()
{
    //  Register for save notification so we can have the announcement viewer update.
    AnnouncementEditorControl1.RegisterForSaveNotification(new System.EventHandler(this.SaveAnnouncementNotification));
}

private void SaveAnnouncementNotification(object sender, System.EventArgs e)
{
    //  We have been notified that the announcement has been updated, so have the viewer refresh.
    AnnouncementViewControl1.RefreshAnnouncement();
}

 

Summary

So that is how I used multicast delegates to solve a problem in a real world scenario.

I did have one additional problem caused by the multicast delegate though.  In my announcement editor control, I was using an HTML editor server control.  It's one of those third party server controls you have to pay for.  It had its own save button.  As it turns out, I was able to remove the save button, which was my preference anyway.  But, what if I wanted it to be available to the user?  The problem is that it has its own event type.  That HTML editor server control posts one event for any button that is pushed in its toolbar.  That single event is passed an event argument that contains information that lets you know which button was actually pushed.  The problem is, how do you handle the event once you know that it was the save button that was clicked?  I don't want to duplicate the code for persisting the announcement, so the most common solution is to make the event directly call the method that is mapped to my original save button.  However, that is no longer good enough.  Remember, I have multiple methods mapped when my original save button is clicked.  I need that functionality duplicated.  What I really need is to be able to actually raise the button click event on my original save button programmatically from the HTML editor's button click event.

That asks the question, how do I actually raise a button click event just as though the user pushed the button?  For the answer to that, click here.
 

 

Copyright ©2006 Joe Rattz
Permalink |  Trackback

Comments (10)  
Re: C# Multicast Delegates - A Practical Example    By Yovav Gad on 7/5/2007 8:31:38 PM
This is a great article - Thanks !!!

Re: C# Multicast Delegates - A Practical Example    By Mikhail on 10/22/2008 8:59:51 PM
very nice job. Thank you

Re: C# Multicast Delegates - A Practical Example    By Rajesh B Patil on 5/8/2009 4:59:08 AM
Wel done.

Re: C# Multicast Delegates - A Practical Example    By dharmendra and piyush on 9/2/2009 3:32:34 PM
hi dude
thank u for giving us valueble info.

Re: C# Multicast Delegates - A Practical Example    By Albert on 11/11/2009 4:24:37 AM
This is very simple and good way of making people understand about multicast delegate. Thanks for the nice article.

Re: C# Multicast Delegates - A Practical Example    By Rohan on 12/22/2009 1:05:46 AM
This is a great article, thanks for explaining so nicely.

Re: C# Multicast Delegates - A Practical Example    By Ravi on 12/24/2009 8:05:46 AM
excellent Sir, nice article

Re: C# Multicast Delegates - A Practical Example    By yogesh dige on 1/12/2010 2:59:40 AM
greate exxmple thnx dude..

Re: C# Multicast Delegates - A Practical Example    By Mansi patel on 3/31/2010 2:13:59 AM
nice example Thank you ...

Re: C# Multicast Delegates - A Practical Example    By Re: C# Multicast Delegates - A Practical Example on 4/2/2010 6:13:32 AM
Re: C# Multicast Delegates - A Practical Example

 
Module Border Module Border
My Book

 

Module Border Module Border
Blog Archive
   
    

  Home|Freebies|Blog|Services|Articles|ASP.NET Depot|DotNetNuke Central|Contact Us
  Copyright 2005 Netsplore Terms Of Use Privacy Statement