Frederik Vig – ASP.NET developer

Follow me

Archive for August 2009

Add class attribute to body element with ASP.NET web forms and Master Pages

Often I have to add a class to the HTML body element. This is a little code snippet that allows you to easily do this.

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site1.master.cs" Inherits="WebApplication1.Site1" %>
 
<!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>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body runat="server" id="BodyTag">
    <form id="form1" runat="server">
    ...
    </form>
</body>
</html>

Add the public property BodyClass.

public string BodyClass
{
    set
    {
        BodyTag.Attributes.Add("class", value);
    }
}

Then in your .aspx, you need to make the Master Page strongly typed by adding MasterType (you can also manually cast it to the right type).

<%@ MasterType VirtualPath="~/Site1.Master" %>

You’ll now have access to the Master Pages BodyClass property.

Master.BodyClass = "home";
 
// Or by manually casting it
((Site1)Master).BodyClass = "home";
...
<body id="ctl00_BodyTag" class="home">
...

EPiServer web controls: MenuList and PageTree

Both the MenuList and PageTree control are controls that you’ll come across when building the navigation for your EPiServer site. Usually you’ll start out with the MenuList for the main navigation, and use the PageTree for the sub navigation.

MenuList

Templates

A few of its public properties.

Examples

By default the MenuList will filter out pages that are not published or that the user has no access to. It will also filter out pages where the property visible in menu is unchecked.

<EPiServer:MenuList runat="server" ID="MainMenu">
    <HeaderTemplate><ul id="MainMenu"></HeaderTemplate>
    <ItemTemplate><li><EPiServer:Property runat="server" PropertyName="PageLink" /></li></ItemTemplate>
    <SelectedTemplate><li><EPiServer:Property runat="server" CssClass="active" PropertyName="PageLink" /></li></SelectedTemplate>
    <FooterTemplate></ul></FooterTemplate>
</EPiServer:MenuList>
protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
 
    MainMenu.PageLink = PageReference.StartPage;
    MainMenu.DataBind();
}

Markup rendered

<ul id="MainMenu">
<li><a href="/en/News/">News</a></li>
<li><a href="/en/Events/">Events</a></li>
<li><a href="/en/Documents/">Documents</a></li>
<li><a class="active" href="/en/Examples/">Examples</a></li>
</ul>

Separator template

I don’t use the separator template often. However, sometimes I need to add a class to distinguish the first li element.

<ul id="MainMenu">
<li class="first"><a href="/en/News/">News</a></li>
<li><a href="/en/Events/">Events</a></li>
<li><a href="/en/Documents/">Documents</a></li>
<li><a class="active" href="/en/Examples/">Examples</a></li>
</ul>

To do this I use a combination of the header and separator template.

<EPiServer:MenuList runat="server" ID="MainMenu">
    <HeaderTemplate><ul id="MainMenu"><li class="first"></HeaderTemplate>
    <ItemTemplate><EPiServer:Property runat="server" PropertyName="PageLink" /></li></ItemTemplate>
    <SelectedTemplate><EPiServer:Property runat="server" CssClass="active" PropertyName="PageLink" /></li></SelectedTemplate>
    <SeparatorTemplate><li></SeparatorTemplate>
    <FooterTemplate></ul></FooterTemplate>
</EPiServer:MenuList>

Sometimes you need to add a few span tags inside the anchors. Mostly just for adding more background images. When this happens you cannot use the EPiServer:Property control for this. Instead you use a combination of regular HTML and data binding syntax.

 <ItemTemplate>
	<li>
		<a href="<%# Container.CurrentPage.LinkURL %>">
			<span class="l"></span><span class="c"><%# Container.CurrentPage.Property["PageName"].ToWebString() %></span><span class="r"></span>
		</a>
	</li>
</ItemTemplate>

PageTree

The PageTree control is the one I use when I need a more complex navigation than a simple list. It has a lot of templates that help with most things I come a cross. However it can be a little hard at first to know which of the templates to use.

Both MenuList and PageTree inherit from PageTreeData, which means they have almost identical public properties. They also share the same default filtering settings.

I think the easiest way to show you what the different templates do is with an example.

<EPiServer:PageTree ShowRootPage="false" runat="server" id="SubMenu">
<HeaderTemplate>
    <div id="SubMenu"><!-- HeaderTemplate -->
</HeaderTemplate>
	<IndentTemplate>
		<ul> <!-- IndentTemplate -->
	</IndentTemplate>
 
	<ItemHeaderTemplate>
		<li> <!-- ItemHeaderTemplate -->
	</ItemHeaderTemplate>
 
	<ItemTemplate>
		<EPiServer:Property PropertyName="PageLink" runat="server" /> <!-- ItemTemplate -->
	</ItemTemplate>
 
	<ExpandedItemTemplate>
	    <EPiServer:Property runat="server" PropertyName="PageLink" CssClass="ExpandedItemTemplate" /> <!-- ExpandedItemTemplate -->
	</ExpandedItemTemplate>
 
	<ExpandedTopTemplate>
	    <EPiServer:Property runat="server" PropertyName="PageLink" CssClass="ExpandedTopTemplate" /> <!-- ExpandedTopTemplate -->
	</ExpandedTopTemplate>
 
	<SelectedItemTemplate>
	            <EPiServer:Property CssClass="SelectedItemTemplate" PropertyName="PageName" runat="server" /> <!-- SelectedItemTemplate -->
	</SelectedItemTemplate>
 
	<SelectedExpandedItemTemplate>
	    <EPiServer:Property runat="server" PropertyName="PageLink" CssClass="SelectedExpandedItemTemplate" /> <!-- SelectedExpandedItemTemplate -->
	</SelectedExpandedItemTemplate>
 
	<SelectedExpandedTopTemplate>
	    <EPiServer:Property runat="server" PropertyName="PageLink" CssClass="SelectedExpandedTopTemplate" /> <!-- SelectedExpandedTopTemplate -->
	</SelectedExpandedTopTemplate>
 
	<ItemFooterTemplate>
			</li> <!-- ItemFooterTemplate -->
	</ItemFooterTemplate>
 
	<UnindentTemplate>
		</ul> <!-- UnindentTemplate -->
	</UnindentTemplate>
	<FooterTemplate>
	    </div> <!-- FooterTemplate -->
	</FooterTemplate>
</EPiServer:PageTree>

To connect our MainMenu (MenuList) with our newly created SubMenu (PageTree), we’ll use MenuLists OpenTopPage property (returns a PageReference to the open top page).

public MenuList MenuList
{
    get { return _menuList; }
    set { _menuList = value; }
}
 
protected override void OnLoad(EventArgs e)
{
	base.OnLoad(e);
 
	SubMenu.PageLink = MenuList.OpenTopPage;
	SubMenu.DataBind();
}

We need to connect the main menu with the sub menu. Set the MenuList property in your master page.

// The registered user controls for the main and sub menu
...
<public:MainMenu runat="server" ID="MainMenu" />
...
<public:SubMenu runat="server" ID="SubMenu" />
protected override void OnLoad(System.EventArgs e)
{
    base.OnLoad(e);
 
    if (SubMenu != null && MainMenu != null)
    {
	SubMenu.MenuList = MainMenu.MenuList;
    }
    ...
}

The markup rendered should look something like this.

<div id="SubMenu"><!-- HeaderTemplate -->
	<ul> <!-- IndentTemplate -->
		<li> <!-- ItemHeaderTemplate -->
			<a href="/en/Examples/File-explorer/">File Explorer</a> <!-- ItemTemplate -->
		</li> <!-- ItemFooterTemplate -->
		<li> <!-- ItemHeaderTemplate -->
			<a href="/en/Examples/Registration/">Registration</a> <!-- ItemTemplate -->
		</li> <!-- ItemFooterTemplate -->
		<li> <!-- ItemHeaderTemplate -->
			<a href="/en/Examples/Subscribe/">Subscribe</a> <!-- ItemTemplate -->
		</li> <!-- ItemFooterTemplate -->
		<li> <!-- ItemHeaderTemplate -->
			<a href="/en/Examples/Demo/">Demo</a> <!-- ItemTemplate -->
		</li> <!-- ItemFooterTemplate -->
		<li> <!-- ItemHeaderTemplate -->
			<a href="/en/Examples/Search/">Search</a> <!-- ItemTemplate -->	
		<li> <!-- ItemHeaderTemplate -->
			<a class="ExpandedTopTemplate" href="/en/Examples/Contact/">Contact</a> <!-- ExpandedTopTemplate -->
			<ul> <!-- IndentTemplate -->
				<li> <!-- ItemHeaderTemplate -->
					<a class="ExpandedItemTemplate" href="/en/Examples/Contact/Test/">Test</a> <!-- ExpandedItemTemplate -->
					<ul> <!-- IndentTemplate -->
						<li> <!-- ItemHeaderTemplate -->
							<a class="SelectedExpandedItemTemplate" href="/en/Examples/Contact/Test/Test2/">Test2</a> <!-- SelectedExpandedItemTemplate -->
						</li> <!-- ItemFooterTemplate -->
					</ul> <!-- UnindentTemplate -->
				</li> <!-- ItemFooterTemplate -->
			</ul> <!-- UnindentTemplate -->
		</li> <!-- ItemFooterTemplate -->
	</ul> <!-- UnindentTemplate -->
</div> <!-- FooterTemplate -->

I recommend clicking around a little to see when the different selected templates kick in.

Other resources

Other posts in this series

Adding CSS and JavaScript files dynamically to your ASP.NET page

When starting a new project I always create a Master Page that holds the content that is most used across the site. In my Master Page I have a PlaceHolder for my JavaScript files at the bottom of the page, right before the closing body tag.

<body>
<form id="form1" runat="server">
...
</form>
    <asp:PlaceHolder runat="server" ID="phdBottomScripts" />
</body>
public PlaceHolder BottomScriptsPlaceHolder
{
    get
    {
        return phdBottomScripts;
    }
}

The reason for having it at the bottom instead of the head is performance.

Now I have the ability to add JavaScript files to the bottom and CSS and JavaScript files to the head (through the pages Header property).

Lets add two methods for adding CSS and JavaScript files.

// using System.Web.UI.HtmlControls;
public static HtmlLink CreateCssLink(string cssFilePath, string media)
{
	var link = new HtmlLink();
	link.Attributes.Add("type", "text/css");
	link.Attributes.Add("rel", "stylesheet");
	link.Href = link.ResolveUrl(cssFilePath);
	if (string.IsNullOrEmpty(media))
	{
		media = "all";
	}
 
	link.Attributes.Add("media", media);
	return link;
}
 
public static HtmlGenericControl CreateJavaScriptLink(string scriptFilePath)
{
	var script = new HtmlGenericControl();
	script.TagName = "script";
	script.Attributes.Add("type", "text/javascript");
	script.Attributes.Add("src", script.ResolveUrl(scriptFilePath));
 
	return script;
}

The media attribute is to specify which media types the CSS file should be applied to.

Media types

  • all
  • braille
  • embossed
  • handheld
  • print
  • projection
  • screen
  • speech
  • tty
  • tv

Example

protected override void OnLoad(EventArgs e)
{
	base.OnLoad(e);
 
	Page.Header.Controls.Add(Helper.CreateJavaScriptLink("~/Scripts/swfobject.js"));
	Page.Header.Controls.Add(Helper.CreateCssLink("~/Styles/styles.css", "screen"));
}
<head>
...
<script type="text/javascript" src="/Scripts/swfobject.js"></script>
<link type="text/css" rel="stylesheet" href="/Styles/styles.css" media="screen" />
</head>

To add JavaScript files to the bottom we need to add MasterType to our .aspx file to make my Master Page strongly typed (and thus able to access the BottomScriptsPlaceHolder property).

<%@ MasterType VirtualPath="~/MasterPages/MasterPage.master" %>
Master.BottomScriptsPlaceHolder.Controls.Add(Helper.CreateJavaScriptLink("~/Scripts/master.js"));
...
<script type="text/javascript" src="/Scripts/master.js"></script>
</body>

Other methods

Response.Write method

<link href="<%= ResolveUrl("~/Styles/Styles.css") %>" rel="stylesheet" type="text/css" />

ClientScriptManager

From MSDN.

The ClientScriptManager class is used to manage client scripts and add them to Web applications

Methods of the ClientScriptManager class.

ResolveUrl and ResolveClientUrl

Simply put, the difference between these two methods is that ResolveUrl will create a path from the sites root (/Styles/Styles.css), while ResolveClientUrl will create a path that is relative from the page the user is on. (../Styles/Styles.css).

© Copyright Frederik Vig. Based on Fluid Blue theme