Click here to Skip to main content
15,881,715 members
Articles / Web Development / ASP.NET
Article

XP Style Navigation Bar Server Control with collection property and embedded resources

Rate me:
Please Sign up or sign in to vote.
4.87/5 (13 votes)
13 Oct 20076 min read 76.4K   998   71   16
An article that explains how to create a custom server control with collection property and embedded resources

Index

Introduction

This article explains how to create an ASP.NET server control which has a collection property and uses embedded web resources. In this, we will be creating an XP look and feel navigation server control. This article will focus on:

  • How to create a server control with collection property
  • Show collection editor on the designer for collection property
  • Implement Web Resources concept
Navigation bar rendered in internet explorer

Why this Article?

Why am I writing this control? Creating server control with properties is not at all a tough job. But creating a control which has a collection <code>property requires a few steps. I have not found any good examples that manage with collection properties and design time support. This article focuses on creating collection classes and adding the collection items from Visual Studio Designers collection editor.

A custom server control should be always easy to use like other ASP.NET controls. Many custom controls use JavaScripts and images, and instruct the users to copy those to a location on the server to get the control working. In this article, I will explain how this can be avoided by embedding resources in the Assembly.

Introduction to ASP.NET Server Controls

This article is not a step by step explanation of creating a server control. That has been written by several writers before. If you are reading this article without any prior knowledge of ASP.NET Custom Server Controls, I refer you to read this before you continue reading this article.

ASP.NET allows developing custom reusable controls. These controls are inherited from System.Web.UI.WebControl. When a new control library project is created, Render() method in WebControl class will be overridden. ASP.NET processes each control in the page and asks them to render by calling the Render() method of control. Render() method takes HTMLTextWriter object and writes rendered HTML to the response. In this example, I have also overridden the OnInit() method to register the startup client side scripts.

Class Diagram

Class diagram for Navigation bar control

NavigationBar Members

Name Description
Public method Collapsed Indicates whether the control has to be collapsed or expanded
Public methodHeaderCssClassStyle sheet class name for the header text
Public methodHeaderFontFont name for the header text
Public methodHeaderFontSizeSpecifies header font size
Public methodHeaderForeColorSpecifies color of the header text
Public methodHeaderTextMenu header text. By default this will be "Menu Header"
Public methodItemsCollection of NavigationBarItem objects
Public methodItemsBgColorBackground color of items cell
Public methodItemsCssClassStyle sheet class for items
Public methodItemsFontFont name for navigation bar item
Public methodItemsFontSizeFont size for navigation bar item
Public methodMenuItemSpaceSpace between each menu item
Public methodPanelColorColor of the menu container. By default this will be XP blue color
Public methodSpacerWidthWidth between left image and menu item text

NavigationBarItems Collection Class

Collection class holds similar types of objects which are accessible using an index. .NET allows different methods to create collection classes. NavigationBarItemsCollection class holds NavigationBarItem objects. This collection class implements ICollection and IList interfaces, which forces a class to implement collection functionality. Objects are kept inside an ArrayList. The following code snippet shows common functions used in this collection class.

C#
public int Add(NavigationBarItem item)
{
    return this._Items.Add(item);
}

public void Clear()
{
    this._Items.Clear();
}

public void RemoveAt(int index)
{
    this._Items.RemoveAt(index);
}

public int Count
{
    get
    {
        return this._Items.Count;
    }
}

To make collection members accessible through an index, the following property is used:

C#
public NavigationBarItem this[int index]
{
    get
    {
        return (NavigationBarItem)this._Items[index];
    }
    set
    {
        this._Items[index] = (NavigationBarItem)value;
    }
}

This enables a programmer to access NavigationBarItem object from the collection as follows:

C#
NavigationBarItem item = NavigationBar1.Items[1];

Setting Collection Class to Property

C#
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Editor(typeof(System.ComponentModel.Design.CollectionEditor),
typeof(System.Drawing.Design.UITypeEditor)),
PersistenceMode(PersistenceMode.InnerDefaultProperty), MergableProperty(false)]
public NavigationBarItemsCollection Items
{
    get { return _Items; }
}

Simply setting collection class to property won't work correctly in VSDesigner. It will show System.Object when a new item is added through the collection editor. But using code this can be added.

To add items through design view, we need the below attributes to be specified:

C#
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Editor(typeof(System.ComponentModel.Design.CollectionEditor),
typeof(System.Drawing.Design.UITypeEditor)),
PersistenceMode(PersistenceMode.InnerDefaultProperty), MergableProperty(false)]

DesignerSerializationVisibilityAttribute is used to serialize a property on design time. For more information on the attribute, please check MSDN documentation. PersistenceMode is another attribute which tells how a property should be on a page. PersistenceMode.InnerDefaultProperty tells ASP.NET to persist the items as inner tags.

To set this, a class that inherits ControlDesigner is needed. ControlDesigner is the base class which helps to extend design time behavior of a web control. NavigationBarDesigner is a derived class from ControlDesigner. The following snippet shows the overridden Initialize() method.

C#
public override void Initialize(System.ComponentModel.IComponent component)
{
    base.Initialize (component);
    this._NavigationBar = (NavigationBar)component;
}

NavigationBarItemBuilder Class

This class is derived from ControlBuilder class. Most controls in ASP.NET will be associated with ControlBuilder class, which helps to parse both control and its inner tags. NavigationBarItemBuilder overrides methods like AllowWhitespaceLiterals() and HtmlDecodeLiterals(). AllowWhitespaceLiterals() parses white space in control tag content provided a true value is returned. This method always returns true value. So the functionality has been overridden to return a false value. HtmlDecodeLiterals() is overridden to decode HTML characters found on tag content. Check the following snippet:

C#
public override bool AllowWhitespaceLiterals()
{
    return false;
}

public override bool HtmlDecodeLiterals()
{
    return true;
}

Embedding Resources with Control

I have seen many custom controls with usage guidelines like:

  • Copy images to images folder on server
  • Copy js files to include directory on server, etc.

Embedding resources with control is a concept that helps to create a variety of server controls without these prerequisites.

Problems with Control Usage Guidelines

In ASP.NET 1.1, the external resources like stylesheets, JavaScript files are deployed in a package and installed in the client machine, which stop functioning when these files are saved in the incorrect location.

WebResource concept in ASP.NET 2.0 overcame all these problems, so that, all these external resources can be embedded with the assembly and loaded at runtime. While running a page with NavigationBar control, a reference to WebResource.axd can be seen from page's source code, which handles these embedded resources. The querystring variables represent time stamp value and requested resource name. To embed a file, set build action of the file to "Embedded resource". The following image explains how web resources are working.

WebResource architecture

Retrieving from Embedded Resource

EmbeddedResourceManager is a class which manages all embedded resources. The following snippet shows retrieving header image from an embedded resource.

C#
public string HeaderBackground
{
   get
   {
      string BgUrl = _NavigationBar.Page.ClientScript.GetWebResourceUrl
                    (_NavigationBar.GetType(), 
                    "System.Web.UI.WebControls.headerbg.gif");
      return BgUrl;
    }
}

Page.ClientScript.GetWebResourceUrl is used to get the embedded resources URL. GetWebResourceUrl() returns the temporary URL for the resource.

Looking into AssemblyInfo.cs

This section deals with adding embedded resources details in AssemblyInfo.cs file.

C#
[assembly: TagPrefix("System.Web.UI.WebControls", "W3Hearts")]

The above statement is used to set the tagprefix for the control. Here is an example for tagprefix.

XML
<W3Hearts:NavigationBar id=NavigationBar1 runat="server"> 
</W3Hearts:NavigationBar>

Page level tag prefix can be modified by the user. When custom controls are added, Visual Studio editor generates a similar tag in the page header.

XML
<%@ Register Assembly="NavigationBar" Namespace="System.Web.UI.WebControls" 
                            TagPrefix="W3Hearts" %>

The following code is used for the embedded resources:

C#
[assembly: System.Web.UI.WebResource
    ("System.Web.UI.WebControls.NavigationBar.js",
"text/js", PerformSubstitution = true)]
[assembly: System.Web.UI.WebResource
    ("System.Web.UI.WebControls.headerbg.gif", "image/gif")]
[assembly: System.Web.UI.WebResource
    ("System.Web.UI.WebControls.downarrow.gif", "image/gif")]
[assembly: System.Web.UI.WebResource
    ("System.Web.UI.WebControls.left1.gif", "image/gif")]
[assembly: System.Web.UI.WebResource
    ("System.Web.UI.WebControls.spacer.gif", "image/gif")]
[assembly: System.Web.UI.WebResource
    ("System.Web.UI.WebControls.uparrow.gif", "image/gif")]

This specifies the resource name and its type. The resource name should start with the default namespace. This method fails when embedded resources are in subfolders.

JavaScript for Expanding/Collapsing Menu

This control uses NavigationBar.js file for JavaScript functions, which contains the function intended to Expand/Collapse navigation bar. The top and bottom arrow on the right side of the control is loaded from the embedded resource. The following example shows how to retrieve the embedded resource URL in a JavaScript function:

C#
function Toggle(obj,NavigationBarId)
{
    if(document.getElementById(obj).style.display == 'none')
    {
        document.getElementById(obj).style.display = 'block';
        document.getElementById(NavigationBarId + "_Arrow").src =
            '';
    }
    else
    {
        document.getElementById(obj).style.display = 'none';
        document.getElementById(NavigationBarId + "_Arrow").src =
            '';
    }
}

Known Issues with this Control

  • ViewState managing problem for NavigationBarItems
  • Lack of binding data directly from a Datasource

Conclusion

In this article, we dealt with creating custom server control with collection property and embedded resources. Collection property holds a collection of NavigationBarItem objects which can be added from design view.

WebResource is a new concept in ASP.NET 2.0 which helps control developers to use these controls without deploying resource files separately.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer ThoughtWorks
India India
Call me Navaneeth Some years ago--never mind how long precisely, I was doing programs with C and C++. When .NET came, I started with C#,ASP.NET and SQL Server.

Comments and Discussions

 
Questionconvert this menu for asp.net 3.5 Pin
Sudheer Kumar Tiwari21-Dec-11 19:37
Sudheer Kumar Tiwari21-Dec-11 19:37 
Dear Navaneeth,

Same menu is not reflecting in 3.5 even i have make changes in assembly for framework 3.5.0.0
Menu is coming but image is not displaying.

So Please change it for 3.5
QuestionHow can i select any node? Pin
nis2720-May-09 5:40
nis2720-May-09 5:40 
GeneralNeed example Pin
Evgueni Kolossov8-Feb-09 22:42
Evgueni Kolossov8-Feb-09 22:42 
GeneralRe: Need example Pin
N a v a n e e t h9-Feb-09 6:02
N a v a n e e t h9-Feb-09 6:02 
Generalcan't visible Pin
hedingxu8-Nov-08 20:26
hedingxu8-Nov-08 20:26 
GeneralRe: can't visible Pin
hedingxu8-Nov-08 22:12
hedingxu8-Nov-08 22:12 
GeneralRe: can't visible Pin
N a v a n e e t h11-Nov-08 15:18
N a v a n e e t h11-Nov-08 15:18 
GeneralNice Article. Pin
Abhijit Jana21-Aug-08 23:29
professionalAbhijit Jana21-Aug-08 23:29 
GeneralRe: Nice Article. Pin
N a v a n e e t h22-Aug-08 18:24
N a v a n e e t h22-Aug-08 18:24 
Generalitem color Pin
Hamdi DBK18-Nov-07 15:45
Hamdi DBK18-Nov-07 15:45 
GeneralRe: item color Pin
N a v a n e e t h18-Nov-07 18:44
N a v a n e e t h18-Nov-07 18:44 
Generalneed collapsible property Pin
Imran Khan Pathan6-Nov-07 18:13
Imran Khan Pathan6-Nov-07 18:13 
GeneralRe: need collapsible property Pin
N a v a n e e t h6-Nov-07 18:20
N a v a n e e t h6-Nov-07 18:20 
GeneralRe: need collapsible property Pin
Imran Khan Pathan6-Nov-07 18:51
Imran Khan Pathan6-Nov-07 18:51 
GeneralRe: need collapsible property Pin
N a v a n e e t h6-Nov-07 19:33
N a v a n e e t h6-Nov-07 19:33 
GeneralRe: need collapsible property Pin
N a v a n e e t h6-Nov-07 19:42
N a v a n e e t h6-Nov-07 19:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.