Search This Blog

2009-05-27

Call Master page event in Content page

A challenge developers may have using ASP.NET 2.0's master pages and content pages is the ability to notify content pages that something has happened in the master page that may be of interest inside the content page. For this example, let's assume our master page holds a list of buttons, and your content page needs to be notified that a new item is selected.
To solve this, we'll create a delegate.Add this outside of the code behind class to expose it to the content forms.Think of a delegate as a notification system that is avaiable for all to use.When the Master Page's button is clicked, its regular click event fires. Inside this event, the delegate is called to tell any subscribing entities that something great has happened, and they should react.

Code Snippet:
Here's how our master page is set up:

<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<link href="StyleSheet.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div id="wrapper">
<div id="header">
Header Area
</div>
<div id="menuArea">
<asp:Button ID="btnMenu1" runat="server" Text="Menu 1" OnClick="btnMenu1_Click" />
<asp:Button ID="btnMenu2" runat="server" Text="Menu 2" OnClick="btnMenu2_Click" />
</div>
<div id="mainContent">
<asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
</asp:contentplaceholder>
</div>
<div id="footer">
Footer Area
</div>
</div>
</form>
</body>
</html>

And the code behind class for the Master Page:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

#region Public Delegates

// Expose delegates for Master Page Events
public delegate void MasterPageMenuClickHandler(object sender, System.EventArgs e);

#endregion Public Delegates

public partial class MasterPage : System.Web.UI.MasterPage
{
#region Public Properties

private string _currentButton;

public string CurrentButton
{
get { return _currentButton; }
set { _currentButton = value; }
}

#endregion Public Properties

#region Public Events

public event MasterPageMenuClickHandler MenuButton;

#endregion Public Events

#region Page Events

///
/// Handles Page Load Event
///

///
///
protected void Page_Load(object sender, EventArgs e)
{
}

///
/// Handles Button 1 Click Event
///

///
///
protected void btnMenu1_Click(object sender, EventArgs e)
{
// Assign value to public property
_currentButton = "One";

// Fire event to existing delegates
OnMenuButton(e);
}

///
/// Handles Button 2 Click Event
///

///
///
protected void btnMenu2_Click(object sender, EventArgs e)
{
// Assign value to public property
_currentButton = "Two";

// Fire event to existing delegates
OnMenuButton(e);
}

#endregion Page Events

#region Virtual Methods

///
/// Invokes subscribed delegates to menu click event.
///

/// Click Event arguments
protected virtual void OnMenuButton(EventArgs e)
{
if (MenuButton != null)
{
//Invokes the delegates.
MenuButton(this, e);
}
}

#endregion Virtual Methods

}


Now, subscribing to this delegate is easy. In the Page Load of the content page, we simply add an event handler to the public event you created in the master page:

Master.MenuButton +=new MasterPageMenuClickHandler(Master_MenuButton);
One important item to note: to reference Master in this fashion, you'll have to add a MasterType directive to the top of the content page's aspx page.

<%@ MasterType virtualPath="~/MasterPage.master"%>

Delegates are so useful because they allow a class to notify others of an event, without being tied in any way to the subscribing forms. Here's the default.aspx content page code behind:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
/// <summary>
/// Handles Page Load Event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Page_Load(object sender, EventArgs e)
{
Master.MenuButton +=new MasterPageMenuClickHandler(Master_MenuButton);
}

/// <summary>
/// Reacts to Master Page menu click event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Master_MenuButton(object sender, EventArgs e)
{
lblOutput.Text = string.Format("Button {0} was pressed", Master.CurrentButton.ToString());
}
}


And that's how easy it is.

No comments: