Passing Information Between Content and Master PagesBy Scott Mitchell
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!
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:
DataFromPage is a Label Web control in the Master Page's declarative markup. The method
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
Additionally, the Master Page can expose a Web control from its declarative syntax as a read-only property:
To access the Master Page's methods or properties from a content page, reference the Master Page through the
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
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:
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:
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
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.
If you use the |
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
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
Value property values. Therefore, we can use the
delegate, which passes a
object to the event handler, which includes
CommandArgument properties that
we can use to hold the selected
Value property values.
To define an event named
MoodChanged for the Master Page that uses the
CommandEventHandler delegate, use the following syntax:
When the DropDownList's
SelectedIndexChanged event fires we want to raise the Master Page's
event. To accomplish this, add the following code into the DropDownList's
SelectedIndexChanged event handler:
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
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:
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
.aspx file for this content page.
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
@MasterTypedirective. 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.