WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Cooking with ASP.NET
Pages: 1, 2, 3

Recipe 4.4: Communicating Between User Controls

Problem

You have multiple user controls on a page, and one of the user controls needs to send data to another as, for example, when one control takes its form or content from the user's action on another.

Solution

Create a source user control, a destination user control, and a web form that contains both user controls. (See Recipe 4.1 and Recipe 4.2 for detailed steps.) In the source user control, create a custom event and raise the event when the required action is performed, such as when a user completes her entry for a form. In the destination user control, create an event handler to receive the event from the source user control. Finally, "wire" the event raised in the source user control to the event handler in the destination user control in the Page_Load event of the web form. The output of a test page showing one user control communicating with another appears in Figure 4-4. The code for our example application that implements the solution is shown in Examples Example 4-15 through Example 4-23. Example 4-15 shows the .ascx file for the source user control. Example 4-16 and Example 4-17 show the VB and C# code-behind for the source user control. Example 4-18 shows the .ascx file for the destination user control. Example 4-19 and Example 4-20 show the VB and C# code-behind for the destination user control. Example 4-21 shows the .aspx file for the web form used to demonstrate the user controls and their interconnection. Example 4-22 and Example 4-23 show the VB and C# code-behind for the demonstration web form.


Figure 4-4. Communicating between controls output

Discussion

Rather than focus on the basic content and creation of user controls, which is the focus of the previous recipes in the chapter, this recipe instead focuses on the interaction between user controls. The approach we advocate for handling this interaction involves creating a custom event for the source user control and raising the event when the communication is to be initiated, such as when the user clicks a button to complete his entry for the form. In order to receive the event from the source user control, the destination user control must have an event handler tailored for that purpose.

In our approach, creating the custom event for the source user control involves creating a custom event argument class, which provides the ability to add a message to the event arguments. It also involves using a delegate, which is a convenient way to pass to the destination user control a reference to an event handler for the OnSend event raised by the source user control.

We've created an application to illustrate our approach. Because of the unusually high number of interrelated files, this example may appear a bit overwhelming at first, but it is actually pretty straightforward. Keep in mind that there are three basic pieces:

  • A user control that sends a message (the source)

  • A user control that receives the message (the destination)

  • A web form that contains the two user controls and wires them together

The source user control contains only a button that is used to initiate sending a message.

The source user control code-behind contains the bulk of the code. First, we create a custom event argument class to provide the ability to add the message to the event arguments. This class inherits from System.EventArgs and adds a message property, as shown in Example 4-16 (VB) and Example 4-17 (C#).

Next, we define a new delegate signature, customMessageHandler, to allow the MessageEventArgs object to be passed as the event arguments. Without this delegate, you would have to use the EventArgs object, which does not provide the ability to pass custom information. An event is then defined with this type of delegate.

TIP: A delegate is a class that can hold a reference to a method. A delegate class has a signature, and it can only hold references to methods that match its signature. The delegate object is passed to code that calls the referenced method, without having to know at compile time which method will actually be invoked. The most common example is building a generic sort routine, one that allows you to sort any type of data, where you pass to it not only the data to be sorted but also a reference to the comparison routine needed to compare the particular data. The situation here is somewhat similar. In this case, we are passing a message to the destination user control (contained within an instance of MessageEventArgs) as well as a reference to an event handler for the OnSend event raised by the source user control. A delegate provides the best, most convenient way to accomplish this.

Our remaining task in the source user control code-behind is to provide a standard event handler for the send message button click event. In this handler, an instance of MessageEventArgs is created and populated with the message being sent. The OnSend event is then raised, passing a reference to the source user control as the event source and a reference to the messageArgs object containing the message being sent. In our example, this is a simple hardwired message, but it demonstrates the basic principal.

WARNING In C#, the OnSend event must be checked to make sure it is not null before raising the event. Failure to do so will result in an exception being thrown if no handler is wired to the event. This is not required for VB.

Our example's destination user control, which is shown in Example 4-18, contains only a label used to display the message sent from the source user control.

The destination user control code-behind, which is shown in VB in Example 4-19 and in C# in Example 4-20, contains a single method to handle the event raised from the source user control. The signature of the method must match the customMessageHandler delegate defined in the source user control. The only operation performed is to update the label in the user control with the message passed in the event arguments.

In our example, the .aspx file for the web form used to demonstrate the user controls, which appears in Example 4-21, registers the two user controls and instantiates each of the controls.

The code-behind for the demonstration web form, which is shown in VB in Example 4-22 and in C# in Example 4-23, provides the glue for tying the event from the source user control to the destination user control. This is done by adding the updateLabel of the destination user control as an event handler for the OnSend event raised by the source user control. What we're actually doing here is adding a delegate to the source user control's OnSend event's event handler list; that list now consists of just one event handler, but can include more.

TIP: Event delegates in .NET are multicast, which allows them to hold references to more than one event handler. This provides the ability for one event to be processed by multiple event handlers. You can try it yourself by adding a label to the demonstration web form, adding a new event handler in the web form, and then adding your new event handler to the OnSend event's event handler list. This will cause the label on the destination user control and the web form to be updated with the message from the source user control. An example that does this with multiple user controls is shown in Recipe 4.5.

WARNING In VB, when using the event/delegate model, the keyword WithEvents is not used. (Recall that the WithEvents keyword indicates that a declared object variable refers to a class instance that can raise events.) WithEvents and the event/delegate model can be intermixed, but they should not be used for the same event.

See Also

Programming C# or Programming Visual Basic .NET, both by Jesse Liberty (O'Reilly), for more about delegates

Example 4-16. Communicating between controls—source user control code-behind (.vb)

Option Explicit On 
Option Strict On
'-----------------------------------------------------------------------------
'
'   Module Name: CH04UserControlCommSourceVB.ascx.vb
'
'   Description: This module provides the code behind for
'                CH04UserControlCommSourceVB.ascx
'
'*****************************************************************************
Imports System

Namespace ASPNetCookbook.VBExamples
  Public MustInherit Class CH04UserControlCommSourceVB
    Inherits System.Web.UI.UserControl

    'controls on the user control
    Protected WithEvents btnSendMessage As System.Web.UI.WebControls.Button

    'define the delegate handler signature and the event that will be raised
    'to send the message
    Public Delegate Sub customMessageHandler(ByVal sender As System.Object, _
                                             ByVal e As MessageEventArgs)
    Public Event OnSend As customMessageHandler

    '*************************************************************************
    '
    '   ROUTINE: btnSendMessage_Click
    '
    '   DESCRIPTION: This routine provides the event handler for the send 
    '                message button click event.  It creates a new
    '                MessageEventArgs object then raises an OnSend event
    '-------------------------------------------------------------------------
    Private Sub btnSendMessage_Click(ByVal sender As Object, _
                                     ByVal e As System.EventArgs) _
                Handles btnSendMessage.Click
      Dim messageArgs As New MessageEventArgs
      messageArgs.message = "This message came from the source user control"
      RaiseEvent OnSend(Me, messageArgs)
    End Sub  'btnSendMessage_Click
  End Class  'CH04UserControlCommSourceVB

  'The following class provides the definition of the custom event arguments
  'used as the event arguments for the message sent from this control
  'This class simply inherits from System.EventArgs and adds a message property
  Public Class MessageEventArgs
    Inherits EventArgs
    Private mMessage As String
    Public Property message( ) As String
      Get
        Return (mMessage)
      End Get
      Set(ByVal Value As String)
        mMessage = Value
      End Set
    End Property
  End Class  'MessageEventArgs
End Namespace

Example 4-17. Communicating between controls—source user control code-behind (.cs)

//----------------------------------------------------------------------------
//
//   Module Name: CH04UserControlCommSourceCS.ascx.cs
//
//   Description: This module provides the code behind for
//                CH04UserControlCommSourceCS.ascx
//
//****************************************************************************
using System;

namespace ASPNetCookbook.CSExamples
{
  public abstract class CH04UserControlCommSourceCS : System.Web.UI.UserControl
  {
    // controls on the user control
    protected System.Web.UI.WebControls.Button btnSendMessage;

    // define the delegate handler signature and the event that will be raised
    // to send the message
    public delegate void customMessageHandler(System.Object sender,
                                              MessageEventArgs e);
    public event customMessageHandler OnSend;

    //************************************************************************
    //
    //   ROUTINE: Page_Load
    //
    //   DESCRIPTION: This routine provides the event handler for the page 
    //                load event.  It is responsible for initializing the 
    //                controls on the user control.
    //------------------------------------------------------------------------
    private void Page_Load(object sender, System.EventArgs e)
    {
      // wire the click event for the send button
      this.btnSendMessage.Click += 
        new System.EventHandler(this.btnSendMessage_Click);
    }  // Page_Load

    //************************************************************************
    //
    //   ROUTINE: btnSendMessage_Click
    //
    //   DESCRIPTION: This routine provides the event handler for the send 
    //                message button click event.  It creates a new
    //                MessageEventArgs object then raises an OnSend event
    //------------------------------------------------------------------------
    private void btnSendMessage_Click(Object sender,
                                      System.EventArgs e)
    {
      MessageEventArgs messageArgs = new MessageEventArgs( );
      messageArgs.message = "This message came from the source user control";
      if (OnSend != null)
      {
        OnSend(this, messageArgs);
      }
    }  // btnSendMessage_Click
  }  // CH04UserControlCommSourceCS

  // The following class provides the definition of the custom event 
  // arguments used as the event arguments for the message sent from this 
  // control.  This class simply inherits from System.EventArgs and adds 
  // a message property.
  public class MessageEventArgs : System.EventArgs
  {
    private String mMessage;
    public String message
    {
      get
      {
        return(mMessage);
      }
      set
      {
        mMessage = value;
      }
    }  // message
  }  // MessageEventArgs
}

Example 4-21. Communicating between controls—main form (.aspx)

<%@ Page Language="vb" AutoEventWireup="false" 
         Codebehind="CH04UserControlCommTestVB.aspx.vb" 
         Inherits="ASPNetCookbook.VBExamples.CH04UserControlCommTestVB" %>
<%@ Register TagPrefix="ASPCookbook" TagName="SourceControl" 
             Src="CH04UserControlCommSourceVB.ascx" %>         
<%@ Register TagPrefix="ASPCookbook" TagName="DestinationControl" 
             Src="CH04UserControlCommDestinationVB.ascx" %>         
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
  <head>
    <title>User Control Communication Test</title>
    <link rel="stylesheet" href="css/ASPNetCookbook.css">
  </head>
  <body leftmargin="0" marginheight="0" marginwidth="0" topmargin="0">
    <form id="frmUCCommTest" method="post" runat="server">
      <table width="100%" cellpadding="0" cellspacing="0" border="0">
        <tr>
          <td align="center">
            <img src="images/ASPNETCookbookHeading_blue.gif">
          </td>
        </tr>
        <tr>
          <td class="dividerLine">
            <img src="images/spacer.gif" height="6" border="0"></td>
        </tr>
      </table>
      <table width="90%" align="center" border="0">
        <tr>
          <td><img src="images/spacer.gif" height="10" border="0"></td>
        </tr>
        <tr>
          <td align="center" class="PageHeading">
            User Control Communication Test (VB)
          </td>
        </tr>
        <tr>
          <td><img src="images/spacer.gif" height="10" border="0"></td>
        </tr>
        <tr>
          <td align="center">
            <table border="0">
              <tr>
                <td class="PageHeading">
                  Source User Control:
                </td>
              </tr>
              <tr>
                <td bgcolor="#ffffcc" align="center" height="75">
                  <ASPCookbook:SourceControl id="ucSource" runat="server" />
                </td>
              </tr>
              <tr>
                <td>&nbsp;</td>
              </tr>
              <tr>
                <td class="PageHeading">
                  Destination User Control:
                </td>
              </tr>
              <tr>
                <td bgcolor="#ffffcc" align="center" height="75">
                  <ASPCookbook:DestinationControl id="ucDestination" 
                                                  runat="server" />
                </td>
              </tr>
            </table>
          </td>
        </tr>
      </table>
    </form>
  </body>
</html>

Pages: 1, 2, 3

Next Pagearrow