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.
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.
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.
Programming C# or Programming Visual Basic .NET, both by Jesse Liberty (O’Reilly), for more about delegates
Example 4-15. Communicating between controls—source user control (.ascx)
<%@ Control Language="vb" AutoEventWireup="false" Codebehind="CH04UserControlCommSourceVB.ascx.vb" Inherits="ASPNetCookbook.VBExamples.CH04UserControlCommSourceVB" %> <asp:Button ID="btnSendMessage" runat="server" Text="Send Message" />
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-18. Communicating between controls—destination user control (.ascx)
<%@ Control Language="vb" AutoEventWireup="false" Codebehind="CH04UserControlCommDestinationVB.ascx.vb" Inherits="ASPNetCookbook.VBExamples.CH04UserControlCommDestinationVB" %> <asp:Label ID="labMessage" Runat="server">No Message Yet</asp:Label>
Example 4-19. Destination user control code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH04UserControlCommDestinationVB.ascx.vb ' ' Description: This module provides the code behind for ' CH04UserControlCommDestinationVB.ascx ' '***************************************************************************** Imports System Namespace ASPNetCookbook.VBExamples Public MustInherit Class CH04UserControlCommDestinationVB Inherits System.Web.UI.UserControl 'controls on the user control Protected labMessage As System.Web.UI.WebControls.Label '************************************************************************* ' ' ROUTINE: updateLabel ' ' DESCRIPTION: This routine provides the event handler that is the ' recipient of the event raised by the source user control. '-------------------------------------------------------------------------Public Sub updateLabel(ByVal sender As System.Object, _
ByVal e As MessageEventArgs)
'update the label with the message in the event arguments
labMessage.Text = e.message
End Sub 'updateLabel
End Class 'CH04UserControlCommDestinationVB End Namespace
Example 4-20. Destination user control code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH04UserControlCommDestinationCS.ascx.cs // // Description: This module provides the code behind for // CH04UserControlCommDestinationCS.ascx // //**************************************************************************** using System; namespace ASPNetCookbook.CSExamples { public abstract class CH04UserControlCommDestinationCS : System.Web.UI.UserControl { // controls on the user control protected System.Web.UI.WebControls.Label labMessage; //************************************************************************ // // ROUTINE: updateLabel // // DESCRIPTION: This routine provides the event handler that is the // recipient of the event raised by the source user // control. //------------------------------------------------------------------------public void updateLabel(System.Object sender,
MessageEventArgs e)
{
// update the label with the message in the event arguments
labMessage.Text = e.message;
} // updateLabel
} // CH04UserControlCommDestinationCS }
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> </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>
Example 4-22. Communicating between controls—main form code-behind (.vb)
Option Explicit On Option Strict On '----------------------------------------------------------------------------- ' ' Module Name: CH04UserControlCommTestVB.aspx.vb ' ' Description: This module provides the code behind for ' CH04UserControlCommTestVB.aspx ' '***************************************************************************** Namespace ASPNetCookbook.VBExamples Public Class CH04UserControlCommTestVB Inherits System.Web.UI.Page 'controls on the form Protected ucSource As CH04UserControlCommSourceVB Protected ucDestination As CH04UserControlCommDestinationVB '************************************************************************* ' ' ROUTINE: Page_Load ' ' DESCRIPTION: This routine provides the event handler for the page load ' event. It is responsible for wiring the source user ' control to the destination user control. '-------------------------------------------------------------------------Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Load
'wire the event to the destination user control handler
AddHandler ucSource.OnSend, AddressOf ucDestination.updateLabel
End Sub 'Page_Load
End Class 'CH04UserControlCommTestVB End Namespace
Example 4-23. Communicating between controls—main form code-behind (.cs)
//---------------------------------------------------------------------------- // // Module Name: CH04UserControlCommTestCS.aspx.cs // // Description: This module provides the code behind for // CH04UserControlCommTestCS.aspx // //**************************************************************************** using ASPNetCookbook.CSExamples; using System; namespace ASPNetCookbook.CSExamples { public class CH04UserControlCommTestCS : System.Web.UI.Page { // controls on the form protected CH04UserControlCommSourceCS ucSource; protected CH04UserControlCommDestinationCS ucDestination; //************************************************************************ // // ROUTINE: Page_Load // // DESCRIPTION: This routine provides the event handler for the page // load event. It is responsible for initializing the // controls on the page. //------------------------------------------------------------------------private void Page_Load(object sender, System.EventArgs e)
{
// wire the event to the destination user control handler
ucSource.OnSend +=
new
CH04UserControlCommSourceCS.customMessageHandler(ucDestination.updateLabel);
} // Page_Load
} // CH04UserControlCommTestCS }
Get ASP.NET Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.