Practical ASP.NET
Integrating Master Pages and Content Pages
Not content with providing a solution for displaying information from the Content page on its MasterPage, Peter returns to the topic to solve the problem from another direction.
In an earlier column ("Integrating Master Pages + Content Pages + a Little AJAX") I showed one way to display in a MasterPage information from the Content page it was displaying. The problem is relatively common: There is some information that you want to display in the same place on every page (and, as a result, you want to put it on the MasterPage) but the information you want to display is being provided by the Content page.
In that column, I added a property to the MasterPage and accessed it from the Content page using the Page object's Master property. This makes sense if you regard Content page as controlling the operation since it's providing the information and think of the MasterPage as the child of the Content page (not an unreasonable point of view, provided you don't take the "Master" in MasterPage too seriously).
MasterPage in Control
However, you could make a case that the MasterPage should be responsible for its own content and, as a result, the MasterPage should be controlling the process. From that point of view, if you wanted to update a Label on the MasterPage with the title of its Content page, you would use code in the MasterPage. This code, put in the MasterPage's Init, Load or PreRender events, would do the trick:
Me.PageTitleLabel.Text = Page.Title
This solution also means that you have to add code in only one place -- the MasterPage -- instead of having to update every Content page.
Unfortunately, this tactic works only as long as the information you want from the Content page is available from a property on the Page object. However, if the Content page is generating the information to be displayed in the MasterPage, then you'll need to add some code to the Content page. For instance, if you wanted to display the user's name and the page's Title, you could add a property like this to the Content page:
Public ReadOnly Property NameAndTitle() As String
Get
Return User.Identity.Name & ": " & Page.Title
End Get
End Property
Accessing this custom property from the MasterPage is more complicated than accessing on the Page's property because, of course, my NameAndTitle property won't appear on the Page object. To access my custom property, I have to cast the Page object to the type of the Content page. It's not reasonable to cast to every different Content page type but there are at least two ways to avoid doing that:
- Create a base class that inherits from Page and have all of the Content pages on the site inherit from that class instead of from the default Page class.
- Create an interface that defines the property and have the Content page implement it.
If the property appears on all pages and the code in the property is usually the same in every page, the first option is probably the best way to go (if the code in the property does vary from one page to another, you can make the property override-able and replace it with page-specific code, as necessary). If, on the other hand, only some of your pages will need this property or the implementation is different on every page, the second option is probably your best choice.
Adding an Interface
If you do decide to use the Interface in a Web site (as opposed to a Web Project), you'll need to add a class file to the App_Code folder and then replace the default code with an Interface declaration. For some reason, the Add New Item dialog for Web sites doesn't include Interface files. Regardless of how you get there, an Interface that includes my property would look like this:
Public Interface IPHV
Property ReadOnly NameAndTitle() As String
End Interface
To implement the interface in a Content page, I would use code like this to implement the interface and add code to it:
Partial Class CustomerOrders
Inherits System.Web.UI.Page
Implements IPHV
Public ReadOnly Property NameAndTitle() As String _
Implements IPHV
Get
Return User.Identity.Name & ": " & Page.Title
End Get
End Property
Now, in the MasterPage's Load event, I can check to see if a page has implemented my interface and (if it has) access the property, as this code does:
If TypeOf Page Is IPHV Then
Me.PageTitleLabel.Text = CType(Page, IPHV).TitleAndName
End If
So now you have two ways to integrate your MasterPage and Content page: Add properties to your MasterPage that you access from your Content page or add properties to your Content page and access them from your MasterPage. Your choice.
And thanks to Doug Rehnstrom who's been bugging me about this for years.
About the Author
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.