Master Pages
The most important thing to have in the website is a consistent look and feel for the whole website and it involves have a similar colour scheme and similar structure for all the pages on the website. Generally the pages in the website are structured in a way that they have a fixed header, fixed side navigation panels, fixed footer and dynamic centre content. The goal is always not replicate the code in the header, footer and side navigation panels. So we need to have a mechanism by which we can place this code in separate file and when we change those vales the changes should be propagated to all the pages.
Master page in ASP.NET provides this facility. So the way it works is that we have a single top level file named with extension as .master. This master page will contain the overall look and feel of the page. We can define our header, footer and panels in the master page file and we also place a placeholder position where the content of the page will be placed. Then we build up the content pages. These pages will be standard ASP.NET pages wired up with the master page and when they render their content then their content is surrounded with the header, footer and panels from the master page. There can be any number of the master page, content place holders, etc.
The actual code for the master page and content page will look like something below. The master pager will end with the .master extention and it will have the similar attributes that the Page Directive does like the Language. Then there will be top level layout and then we put one or more ContentPlaceHolder and this is where the ASP.NET pages will have their regular content.
The Page will have a link to the master page and then it will have a content control which is linked to the ContentPlaceHolder of the master page. Any content specified will be injected into the ContentPlaceHolder.
<!-- MasterPage.master --> <%@ Master Language="C#" %> <html> <body> <form runat="server"> <h1>My Common Header</h1> <asp:ContentPlaceHolder ID="MainContentPlaceHolder" runat="server" /> </form> </body> </html>
<!-- Page1.aspx --> <%@ Page Language="C#" MasterPageFile="~/MasterPage.master" %> <asp:Content ID="Content1" ContentPlaceHolderID="MainContentPlaceHolder" runat="server"> <asp:Button ID="Button1" runat="server" Text="Button" /> </asp:Content>
Now let’s have a look at the actual code in Visual Studio. So lets create a new asp.net website and delete all the files and folder in it except Default.aspx and Web.Config from the solution explorer. Now add a MasterPage to the site named SiteTemplate.master and add the following code to it. This master page will have the header, footer and the maincontentplaceholder for the site.
Add the following content to the Default.aspx page. At the top of the page we add a reference to the MasterPage. And then we place a Content control wired up to the ContentPlaceHolder of the MasterPage and add the a couple of calendar controls into it.
Now add two more pages to the website named Page1.aspx and Page2.aspx and add the following code to them. Similar to the default.aspx we have added a reference to the MasterPage which will govern the header, footer and side panel of the website and the content control that we have added will be the content that will be different on different pages.
Let’s now have a look as to how the master page injects content into the content pages. We should think it in a way that the content page is the endpoint and it is responsible for dispatching the content and the master page is going to be injected as the child control in the hierarchy of the content page. The other important thing to know is that the actual content that is added to the content page is dropped into the ContentPlaceHolder inside the hierarchy in the master page. But in the end the content is rendered as the normal html content. We can a have a look at the hierarchy in the image below.
When you open the default.aspx in the Design mode then you would notice that the design interface of Visual studio will allow you to edit on the content part of the page and the remaining part of you page which is derived from master is not editable.
Now let see the relationship between the master page and the content with regards to the control hierarchy. So let’s enable the trace at default.aspx.
Now let’s run the site and the trace part looks something like below.
Now as the master page is defining the content of the page hence we need to know a few things for our pages to look the way we want them to look like.
- Title attribute of the pages – This is really important because the title attribute is being defined as the part of the master page and that is where we need to place the title but we need have a distinct title for different pages. It’s really staring forward to do while using master page because the head content is marked as runat server and the title attribute takes it value from the content page title. So we could have the default title of the site in the mater page as shown below.
And then we can set the Title of the content pages which will overwrite the default title in the master page.
- Now on some of the page we might want to hide our side panel so what we need to do is add a panel and add the code for the left pane inside it
Now let’s add a property to the MasterPage using which we will use to set the visibility of the Left Panel.
Now we access this property for hiding and showing the visibility of the left pane by accessing the master property for this page in the pageload method.
Another way to do this is to use the VirtualPath property in the MasterType directive and set it to the masterpage of the site.
Now as we have specified the MasterType at the masterpage so we do not need to typecast it as the SiteTemplate and we can simply directly access the Master Page.
- We can set the masterpage of the content page in the code as well by setting the Page.MasterPageFile but for it work without exception we need to call it in Page_PreInit.
Nested Master Pages
It is perfectly alright to have a MasterPage for the MasterPage as well. So as you can see in the image below we have defined the MasterPageFile attribute in the Master directive of a master page. The reason to do this is to add an addition level of layout. Also you need to see that in the child master page we need to specify the content in the ContentControl just like the content page. But we need to be careful that to access the ContentPlaceHolder of the root master page then we need to redeclare it in the child masterpage.
<!-- SiteTemplate.master --> <%@ Master Language="C#" %> <html> <body> <form runat="server"> <h1>common header</hl> <asp: ContentPIaceHoIder" runat="server" />
<!-- SecondaryTempIate.master --> <%@ Master Language="C#" MasterpageFile="~/SiteTemplate.master" %> <asp: ContentPlaceholderID="mainContentPlaceholder" runat="server"> <table><tr><td> <asp:ContentPlaceholder ID="leftContentPlaceholder" runat="server" /> </td><td> <asp:ContentPlaceholder ID="rightContentPlaceholder" runat="server" /> </tr></table> </asp :Content>
Let’s see this in action by creating a new MasterPage
Let’s add a Content Panel for the head content so that if someone wants to access the head container in the root page then they can do that. Also let’s add a fieldset in the mainContentPlaceHolder with a legend.
Now let’s add a Page3.aspx which will use this SecondaryTemplate.master as the masterpage and add its content in the content place holder.
Themes in ASP.NET
Themes are a useful way to give a consistent look and feel to the controls throughout the application. It is a consolidation of UI elements by the use of stylesheets, skin files, images,etc. Let’s see how themes can be added and used in the application. So Theme is a directory in the application level directory in the App_Themes directory and it can contain zero or more .css files and all .css files are implicitly referenced.
This will add two directories added by this option.
Let’s add a stylesheet to this directory. And add the code shown below to it.
Now let’s add a new page which does not uses any maasterpage and add the following code to it.
When we run our application we will see that the textboxes will have the colo as specified in our theme css file.
The Theme folder may also contain one or more .skin files. A skin file will contain control declarations with default attributes. This will provide a consistent look and feel for the controls that use that skin. We did not put the ID against the controls because we do not want it to apply. We can also put the ID against the controls so that the controls that indivisually want to use that style can do that by referring the ID.
<asp:button runat="server" borderStyle="Solid" borderwidth="2px" bordercolor="#66ff66" backcolor="#99ffff" /> <asp:calendar runat="server" borderStyle="Solid" borderwidth="2px" bordercolor="#66ff66" backcolor="#99ffff" />
Also the theme folder may contain zero or more subdirectories with resources like images or scripts. So all the resources used in the theme could be placed here.
Let’s see this in action. Let’s add a new skin file in our theme1.
Now add the code to this theme file as shown in the image below. The first thing that we need to do is add SkinID to the controls in the MyTheme.skin, if we want to use these control styles on a per control basis.
Now let’s go back to MyThemedPage.aspx and use this style. Now as we have applied the Theme1 to the MyThemedPage.aspx the textboxes there will automatically pickup the style of the textbox which has no SkinID. If we want to use a style that has a skinid then you would need to add that skinid to the control we want to apply the style to. So the textbox1 will have the cssclass foo applied to it will be foo and textbox2 will have the cssclass bar applied to it.
A very simple thing to do is replicate our theme. We can just copy the Theme1 and paste it into the app_Themes folder.
We can then edit the css file in this skin very easily and use it as it already has the same structure and the class named and skin id are all the same and we change or add or delete styles in the css file.
Now let’s add a calendar control to the MyThemedPage.aspx and apply professional1 theme to it. It would look something like below as shown.
Now go back to the Source mode. We will see something like as shown below.
We will copy that calendar code and paste it in the Theme1àMyTheme.skin and remID and add a SkinID as professional.
And now we could use that in our themed page.
Let’s add a images folder and add an image to it. Then we would add a asp:Image control and reference that image into it.
Now we will utilize this image in our MyThemedPage folder.
We would see something like bleow.
What we did before was applied the theme to the page level and now what I am going to do is apply that theme to all the pages in my site by specifying the same in the web.config file. This will impliclitly include a reference to the theme file into all the pages of my site.
Now let’s see how the theme actually works. The way we saw to set the theme on the web.config sets the theme globally and if do not want that theme to certain pages we can override by specify a different theme for that page in the Page directive of that page.
We can also set up the themes programmatically. We need to set the theme in the PreInit event handler of the page.
We can also set the themes globally dynamically.
- We could subscribe to PreRequestHandlerExecute and wireup a PreInit handler on the fly.
- Then set the theme in the PrInit handler and that will apply the changes to all the pages.
- This can be stored in Profile, session, config,etc.
- Same technique works for master pages as well.
<%-- File:Global.asax --%> <%@ Application Language="C#" %> <script runat="server"> void Application_PreRequestHandlerExecute(object src, EventArgs e) { Page p = this.Context.Handler as Page; if(p!=null) p.PreInit += new EventHandler(page_PreInit); } void page_PreInit(object sender, EventArgs e) { Page p = this.Context.Handler as Page; if(p!=null) p.Theme = (string)Context.Profile["theme"]; } </script>
Navigation Controls
In ASP.NET 2.0 3 new site navigation controls were introduced.
- TreeView
- Menu
- SiteMapPath
All these 3 controls can use SiteMapProvider which derives its default data source from web.sitemap and it is a standard xml format for page.navigation. Let’s see how this works. Let’s add a sitemap to our site
Let us add the sitemapnodes to it hierarchal.
Now let’s go back to the MasterPage and go to the Navigation in the Toolbox and use the TreeView , menu and sitemappath.
This is how it looks
The image below shows the hierarchy of the navigation controls.
The Code for this post is available here.
Any questions, comments and feedback is most welcome…