When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, January 31, 2007

Passing Information Between Content and Master Pages

By Scott Mitchell


Introduction


When graphic designers create a layout for a Web site, they typically break down page layout into distinct regions, such as a common header that includes the logo and various navigation links, a left navigation menu perhaps, the main content area, and perhaps some sort of site map or legalese at the footer of the page. ASP.NET 2.0 makes defining these regions and applying them to multiple pages across a website a breeze with Master Pages. A Master Page allows a page developer to define a site-wide layout, marking what regions are customizable on a page-by-page basis. For more on using Master Pages and their advantages, see A Sneak Peak at MasterPages in ASP.NET 2.0.

One common challenge that faces page developers using Master Pages is how to pass information from a Master Page to its content page, or vice-a-versa. A Master Page might contain a DropDownList control that when its selected index changes, the corresponding content page needs to have its display updated. Or perhaps some action in the content page needs to update the appearance of the Master Page. In this article we will explore techniques for passing information between a Master Page and its content page. Read on to learn more!

- continued -

Master Page and Content Page Design Basics


As a website grows, new content pages will no doubt be added and associated with existing Master Pages. Or existing content pages that use MasterPage X might be updated to use Master Page Y instead. Consequently, it's smart to design your Master Pages so that there is no reliance on their content pages. That is, a Master Page shouldn't assume that its content page possesses a particular method or that it has a specific set of Web controls defined in its declarative markup. Such a Master Page is said to be loosely-coupled with its content page; if the Master Page expects particular methods or Web controls on its corresponding contnet pages, then it's said to be tightly-coupled.

It's possible for a Master Page to be loosely-coupled to its content page, but for the content page to be tightly-coupled to the Master Page. For example, the Master Page may make no assumptions and not base any functionality on its content page's methods or markup, but the page may assume that the Master Page has a particular method or Web control present. Ideally, a page will be loosely-coupled with its Master Page, but if information needs to be passed between a Master Page and its content page (or vice-a-versa), there must be some level of coupling, either from the Master Page to the content page (bad) or the content page to the Master Page (better). The demos in this article establish a tight-coupling from the content pages to their Master Pages, but retain a loose-coupling from the Master Pages to their content pages.

Why the Tight-Coupling From the Content Page to Master Page is Preferred
You may be wondering why I recommend a coupling from the content page to the Master Page rather than the other way around. When there exists a coupling from A to B, modifying B typically requires a corresponding modification to A. Since I expect that most websites have far fewer Master Pages than content pages, and that Master Pages are less likely to have their tightly-coupled interface modified than in a content page, from a logistics standpoint it makes sense to introduce the coupling from content pages to Master Pages. Secondarily, this coupling direction just feels "better". When associating a new web page with an existing Master Page, it seems funky to have to stop and think, "OK, now what functionality does this page need to expose in order to work with this Master Page?" If this is a triffle confusing, don't sweat it. I think once you explore the demos the coupling issue will make more sense.

Passing Information from a Content Page to its Master Page


A Master Page can expose its Web controls or methods directly to its content pages. To expose a method, simply mark it as public from the Master Page's code-behind class:

' VB...
Partial Class MasterPageFiles_Main
   Inherits System.Web.UI.MasterPage

   Public Sub DisplayDataFromPage(ByVal message As String)
      DataFromPage.Text = message
   End Sub

End Class


// C#
public partial class MasterPageFiles_MainCS : System.Web.UI.MasterPage
{
   public void DisplayDataFromPage(string message)
   {
      DataFromPage.Text = message;
   }

}

Here DataFromPage is a Label Web control in the Master Page's declarative markup. The method DisplayDataFromPage is a public method that can be invoked from the Master Page's content page. The string input passed into this method is assigned to the Label Web control's Text property. Using this method, the Master Page's content page can set the text displayed in the DataFromPage Label.

Additionally, the Master Page can expose a Web control from its declarative syntax as a read-only property:

' VB...
Partial Class MasterPageFiles_Main
   Inherits System.Web.UI.MasterPage

   Public ReadOnly Property DataFromPageLabelControl() As Label
      Get
         Return Me.DataFromPage
      End Get
   End Property

End Class


// C#
public partial class MasterPageFiles_MainCS : System.Web.UI.MasterPage
{
   public Label DataFromPageLabelControl
   {
      get
      {
         return this.DataFromPage;
      }
   }

}

To access the Master Page's methods or properties from a content page, reference the Master Page through the Page.Master property. This property returns an object of type MasterPage, so you'll need to explicitly cast it to the appropriate type before calling its methods or referencing its properties. Alternatively, you can set the @MasterType directive, which adds a property to the auto-generated ASP.NET code-behind class code named Master that is a strongly-typed reference to the specified Master Page.

The following markup in the .aspx file for the content page spells out the Master Page type:

<%@ MasterType VirtualPath="pathToMasterPage" %>

With this directive added (and the .aspx file saved), you can reference the Master Page's public methods and properties programmatically in the content page's code-behind class using Master like so:

' VB...
Partial Class Demos_PassInfoToMasterPage
   Inherits System.Web.UI.Page

   Protected Sub ShowText_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ShowText.Click
      'Call the Main.master Master Page's DisplayDataFromPage method
      

Master.DisplayDataFromPage(TextToShowInMasterPage.Text)



      ' OPTIONAL: Could reference the control directly through the Master Page's DataFromPageLabelControl property
      '

Master.DataFromPageLabelControl.Text = TextToShowInMasterPage.Text


   End Sub
End Class

// C#
public partial class Demos_PassInfoToMasterPageCS : System.Web.UI.Page
{
   protected void ShowText_Click(object sender, EventArgs e)
   {
      // Call the Main.master Master Page's DisplayDataFromPage method
      Master.DisplayDataFromPage(TextToShowInMasterPage.Text);

      // OPTIONAL: Could reference the control directly through the Master Page's DataFromPageLabelControl property
      //

Master.DataFromPageLabelControl.Text = TextToShowInMasterPage.Text;


   }
}

The code shown here, which is available from the download at the end of this article, is from a content page that includes a TextBox named TextToShowInMasterPage and a Button Web control named ShowText. When the ShowText Button is clicked, the Master Page's DisplayDataFromPage method is called, passed the value of the TextBox's Text property. (Alternatively, the Master Page's DataFromPageLabelControl property could be used to reference the Label control in the Master Page, at which point its Text property could be set.) The net result is that entering text into the TextBox on the content page and clicking the Button results in the Master Page's display updating to display this user-entered text.

The Master Page is updated by the text entered in the content page.

Page.Master versus Master
If you use the @MasterType directive to create a strongly-typed Master Page reference in the content page's code-behind class, you must use Master to get a strongly-typed reference. If your code uses Page.Master, you'll get a loosely-typed reference (one whose type is MasterPage and, therefore, requires a cast before the specific Master Page's members can be accessed).

Passing Information from a Master Page to its Content Page


In certain scenarios a Master Page might contain a Web control that, when modified by a user in some fashion, needs to update the corresponding content page. Perhaps the Master Page contains a DropDownList control that, when modified, needs to refresh the page and display data based on the selected item. Personally, I think such functionality should be moved to a separate User Control and that User Control added to the ASP.NET content pages, as needed. However, you may have a situation in which it is imperative that the Master Page pass information to a content page, so it's worth exploring techniques for accomplishing this.

As aforementioned, I'd strongly encourage you to not establish a tight-coupling from the Master Page to the content page. Such a tight-coupling can be avoided by having the Master Page not directly call some content page method, but instead through the judicious use of events. In short, we can create a Master Page that raises an event when some action happens on the Master Page side. This event can pass any additional information needed and then content pages that require this information can "subscribe" to the Master Page's event. (An alternate approach, not explored in this article, is to have the content page assign a delegate to a property in the Master Page. This technique is discussed in Tim Stall's article, Trigger Page Methods from a User Control. While Tim's article deals with User Controls and ASP.NET pages, the concepts apply equally to Master Pages (the User Control) and content pages (the ASP.NET page).)

To illustrate this, imagine that we had a DropDownList in the Master Page. When its selected index changes, we want to notify the content page of the change so that it can update its display accordingly. Start by creating a DropDownList named Moods in the Master Page that lists various moods (Happy, Sad, etc.) and then create an event handler for this DropDownList's SelectedIndexChanged event. Next, we need to define an event for the Master Page, specifying the event handler signature. The event handler signature specifies what input parameters are passed to the event handler. For this example, let's pass the selected DropDownList item's Text and Value property values. Therefore, we can use the CommandEventHandler delegate, which passes a CommandEventArgs object to the event handler, which includes CommandName and CommandArgument properties that we can use to hold the selected ListItem's Text and Value property values.

To define an event named MoodChanged for the Master Page that uses the CommandEventHandler delegate, use the following syntax:

' VB...
Partial Class MasterPageFiles_Main
   Inherits System.Web.UI.MasterPage

   Public Event MoodChanged As CommandEventHandler
End Class

// C#
public partial class MasterPageFiles_MainCS : System.Web.UI.MasterPage
{
   public event CommandEventHandler MoodChanged;
}

When the DropDownList's SelectedIndexChanged event fires we want to raise the Master Page's MoodChanged event. To accomplish this, add the following code into the DropDownList's SelectedIndexChanged event handler:

' VB...
Partial Class MasterPageFiles_Main
   Inherits System.Web.UI.MasterPage

   Public Event MoodChanged As CommandEventHandler

   Protected Sub Moods_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Moods.SelectedIndexChanged
      If Moods.SelectedIndex <> 0 Then
         RaiseEvent MoodChanged(Me, New CommandEventArgs(Moods.SelectedItem.Text, Moods.SelectedValue))
      End If
   End Sub

End Class

// C#
public partial class MasterPageFiles_MainCS : System.Web.UI.MasterPage
{
   public event CommandEventHandler MoodChanged;

   protected void Moods_SelectedIndexChanged(object sender, EventArgs e)
   {
      if (Moods.SelectedIndex != 0 && MoodChanged != null)
         MoodChanged(this, new CommandEventArgs(Moods.SelectedItem.Text, Moods.SelectedValue));
   }

}

Note: In C#, we have to first check that the event is not null before raising it (note the "&& MoodChanged != null" check in the if statement). This is because the event reference is null if no one has subscribed to the event...

The last step is "subscribing" to the event in the content page's that care about the changing of this DropDownList. To subscribe to the event we need to programmatically specify in the content page that when the Master Page's MoodChanged event fires that a particular event handler defined in the content page should execute. The following code illustrates how to establish this binding between the event and the event handler in C# and VB:

' VB...
Partial Class Demos_PassInfoToPage
   Inherits System.Web.UI.Page

   Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
      'Wire up the event (MoodChanged) to the event handler (MoodChangedFromMasterPage)
      AddHandler Master.MoodChanged, AddressOf MoodChangedFromMasterPage
   End Sub

   Private Sub MoodChangedFromMasterPage(ByVal sender As Object, ByVal e As CommandEventArgs)
      Dim moodText As String = e.CommandName
      Dim moodValue As String = e.CommandArgument.ToString

      MoodChangedLabel.Text = String.Format("You have selected mood {0}, which has a value of {1}...", moodText, moodValue)
   End Sub

End Class

// C#
public partial class Demos_PassInfoToPageCS : System.Web.UI.Page
{
   protected void Page_Init(object sender, EventArgs e)
   {
      // Wire up the event (MoodChanged) to the event handler (MoodChangedFromMasterPage)
      Master.MoodChanged += new CommandEventHandler(MoodChangedFromMasterPage);
   }

   private void MoodChangedFromMasterPage(object sender, CommandEventArgs e)
   {
      string moodText = e.CommandName;
      string moodValue = e.CommandArgument.ToString();

      MoodChangedLabel.Text = String.Format("You have selected mood {0}, which has a value of {1}...", moodText, moodValue);
}
}

The Page_Init event handler associates the Master Page's MoodChanged event with the event handler MoodChangedFromMasterPage (and must re-establish this association on each and every postback). Note that the Master property provides a strongly-typed experience. This is because I used the @MasterType directive in the .aspx file for this content page.

The content page is updated by the selected drop-down list item in the Master Page.

Conclusion


Ideally Master Pages and their content pages will be completely independent entities with no need to share information. However, there are scenarios where this cannot be avoided without difficulty. For those situations, there are various techniques, as discussed in this article. To pass information from a content page to a Master Page, the content page can get a strongly-typed reference to the Master Page through use of the @MasterType directive. This allows the Master Page's public methods and properties to be invoked from content pages with the benefits of compile-time type checking. When passing information from the Master Page to its content pages, I've found the best approach is to have the Master Page raise an event and pass the necessary information. Those pages that need to be notified, then, can subscribe to this event.

Happy Programming!

  • By Scott Mitchell


    Attachments


  • Download the code used in this article
  • Further Readings


  • MasterType in ASP.NET 2.0
  • Working with ASP.NET Master Pages Programmatically
  • ASP.NET Master Pages Overview
  • An Extensive Examination of User Controls (includes a discussion on raising events from a User Control, which is similar to raising events in a Master Page)


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article