Home > .net 3.5, AJAX, JavaScript, Visual Studio 2008 > Creating a Vista-like Menu Bar Custom Control

Creating a Vista-like Menu Bar Custom Control

October 15, 2007

I came across an excellent post on the Itookia website that described creating a Aero-glass like menu bar (from Vista) using just three images and CSS.  Like most cool web components, I have been on a kick lately to find a way to encapsulate the functionality into an ASP.NET server control.

Note: The original CSS source and descriptions are available on the Itookia site.  Thanks to them for the cool CSS.  The control was built using .NET 3.5; however, does not contain any 3.5–specific libraries.  For convenience, I’ve provided both the 2.0 and 3.5 projects.

To begin, take a look at the aforementioned site and familiarize yourself with the CSS and what’s going on.  Even run the demo.  It’s very simple—not even a scrap of JavaScript on the page.

From there, let’s begin to put that into a control. 

Download Control (v3.5) | Download Control (v2.0)

The control will have six components. 

  1. Three images (back.gif, left.png, right.png)
  2. One standard CSS file.
  3. A VistaMenuBar control
  4. A VistaMenuItem class.

Our goal is to generate HTML that forms itself to:

<div id=”vista_toolbar”>

<ul>

<li>

<a href=”#”>

<span>

       <img align=”left” src=”VistaMenuBar/add.gif” alt=”add new” />

Add New

</span>

</a>

</li>

</ul>

</div>

There will be one ListItem element (li) for each “menu item” we add.

There are four attributes to a menu item, the Navigation URL (string), the Image URL (string), the Display Text (string) , and whether or not to right align the item (bool).

Embedding Resources

This control will need those three basic image files and a style sheet for operation.  The best way to handle this is to embed the resources into the control—rather than relying on the user to have the files in the correct place.

To embed the resources (and create an Embedded Resource…):

  1. Add the files to your project.  If you look at the image above, you’ll see a folder called VistaMenuBar with the files inside.
  2. Set the Build Action property of each of the files to “Embedded Resource”.
  3. Add a line in the AssemblyInfo.cs file for each of the resources.

[assembly: WebResource("TSCustomControls.VistaMenuBar.VistaMenuBar.css", 

        "text/css",

        PerformSubstitution=true)]

[assembly: WebResource("TSCustomControls.VistaMenuBar.back.gif",

        "image/gif")]

[assembly: WebResource("TSCustomControls.VistaMenuBar.left.png",

        "image/png")]

[assembly: WebResource("TSCustomControls.VistaMenuBar.right.png",

        "image/png")]

Your code will be different.  Resources are named according to their location and namespace.

Namespace.PathToFile.FileName >> 
  TSCustomControls.VistaMenuBar.back.gif

Note: You may need to add a reference to System.Web.UI to use WebResource.

You may notice that the VistaMenuBar.css file has an additional attribute, PerformSubstitution.  That’s because we need our CSS file to consume these Embedded Resources as well.

There are three classes you’ll need to modify in the base CSS (if you’re getting it from Itookia; the three that point to images.

Replace the url attribute code with a reference to your WebResource.  Here’s an example for the “#vista_toolbar ul” style’s background-image:

background-image:  url(‘<%=WebResource(“TSCustomControls.VistaMenuBar.back.gif”)%>’);

The PerformSubstitution allows this functionality to work.  Good deal!

Creating the Control

Instead of a standard WebControl, this control will need to inherit from the DataBoundControl base class.  This allows us to use DataSource and grants access to the PerformingDataBinding method.

public class VistaMenuBar : DataBoundControl { }

Adding public properties.  Next, add four public properties to hold the four attributes previously discussed.  In this example, they’re named NavigateUrl, ImageUrl, Text, and AlignRight and each are Bindable. 

In addition, set the default value to match the name of the property—this eases the use of the MenuItem object we’ll create later.

Here’s an example of the NavigateUrl property.

[Bindable(true)]

[Category("Appearance")]

[DefaultValue("NavigateUrl")]

[Localizable(true)]

public string NavigateUrl

{

get

       {

              String s = (String)ViewState["NavigateUrl"];

             return ((s == null) ? “NavigateUrl” : s);

}

set

       {

ViewState["NavigateUrl"] = value;

       }

}

Overriding methods.  Our first method to override is the OnPreRender method.  Remember the embedded CSS file we added, we need to populate that on our page BEFORE the control loads.

protected override void OnPreRender(EventArgs e)

{

base.OnPreRender(e);

 

       string includeLocation =

              Page.ClientScript.GetWebResourceUrl(this.GetType(),

             “TSCustomControls.VistaMenuBar.VistaMenuBar.css”);

HtmlLink cssLink = new HtmlLink();

       cssLink.Href = includeLocation;

       cssLink.Attributes.Add(“rel”, “stylesheet”);

       cssLink.Attributes.Add(“type”, “text/css”);

       this.Page.Header.Controls.Add(cssLink);

}

This code first runs all base OnPreRender methods, then grabs the Embedded Resource’s URL (handed from WebResource.axd) and pushes a style tag into the header of the page.  The resultant HTML looks something like:

<link href=”/WebResource.axd?d=rU-1RLo4XEyK0VOMEAnIN_nd6CTbmgWvq6yvdQhV50siqXTSQTB
57Bs0xp4W35_nJlUtHKFRqEepGi1t4tkpHVtT9VHRDQvDKchAE7uKv6w1&amp;t=633280611067677145″ rel=”stylesheet” type=”text/css” />

Please memorize that URL—there will be a quiz later (maybe).  If you’re unfamiliar with Embedded Resources, do some Googling—it’s a great way to keep files attached to objects and such.

The second method does the heavy lifting.  The PerformDataBinding method accepts an IEnumerable data source and allows you the freedom to control what happens with the data.  For this control, we want to generate simple HTML.

protected override void PerformDataBinding(IEnumerable retrievedData)

{

 

base.PerformDataBinding(retrievedData);

 

if (this.DataSource != null)

{

Literal literal = new Literal();

StringBuilder output = new StringBuilder();

 

output.AppendLine(“<div id=’vista_toolbar’>”);

output.AppendLine(“<ul>”);

foreach (object dataItem in retrievedData)

{

PropertyDescriptorCollection props =

TypeDescriptor.GetProperties(dataItem);

 

string navigateUrl =

props[this.NavigateUrl].GetValue(dataItem).ToString();

string imageUrl =

props[this.ImageUrl].GetValue(dataItem).ToString();

string text =

props[this.Text].GetValue(dataItem).ToString();

bool alignRight =

Convert.ToBoolean(props[this.AlignRight].GetValue(dataItem));

 

if (alignRight)

{

output.AppendFormat(“<li><a class=’right’ href=’{0}’><span>”,

navigateUrl);

}

else

{

output.AppendFormat(“<li><a href=’{0}’><span>”, navigateUrl);

}

output.AppendLine();

 

if (imageUrl != “”)

{

output.AppendFormat(“<img align=’left’ src=’{0}’ alt=’{1}’ />”,

imageUrl, text);

}

output.AppendFormat(“{0}</span></a></li>”, text);

}

 

output.AppendLine(“</ul>”);

output.AppendLine(“</div>”);

 

literal.Text = output.ToString();

this.Controls.Add(literal);

}

 

}

Woah—lots of code.  It’s actually not too bad, just a bit more to deal with the boxing of the object.  Here’s what it does:

  1. Process the DataBinding.
  2. Verify that the DataSource isn’t null—if it is, skip all this work.
  3. Create a Literal object and a StringBuilder object—that’s where we’ll put our HTML.
  4. For each “data item” object in the IEnumerable collection, loop through.
  5. Reflect into the “data item” object and get it’s properties.  Set those properties to strings and a boolean.  This could be done inline down below—but, it just seems messier that way.
  6. Fill in the blanks with your variables and perform logic depending on what’s passed (not adding image tags, right align, etc).
  7. Output the literal control back to the page.

Adding a VistaMenuItem Class

The last piece is totally optional.  I created a VistaMenuItem object to allow me to pass in a generic List of VistaMenuItems.  Here’s the structure; more on how to use it when we start consuming the control.

public class VistaMenuItem

{

public string Text { get; set; }

       public string ImageUrl { get; set; }

       public string NavigateUrl { get; set; }

       public bool AlignRight { get; set; }

 

       public VistaMenuItem(string text,

string imageUrl,

string navigateUrl, bool alignRight)

        {

            Text = text;

            ImageUrl = imageUrl;

            NavigateUrl = navigateUrl;

            AlignRight = alignRight;

        }

}

Using the Control

On your ASPX form, compile your new control and add it to the page.

<cc1:VistaMenuBar ID=”VistaMenuBar1″ runat=”server” Width=”100%” />

We have two ways we can populate the menu items: pass an IEnumerable DataSource or pass an IEnumerable list of VistaMenuItem objects. 

The difference?  The VistaMenuItems already know what value goes where in the menu.  The DataSource (a DataTable, etc) will require you to specify the NavigateUrl, ImageUrl, Text, and AlignRight properties if your columns do not match the attribute names.  If they do match, it will pre-fill.

Using a quick DataTable as an example, let’s see what we get.  Now, this is just an example—for “manual entry”, I’d suggest using the VistaMenuItems.  The best way, of course, would be to simply provide a DataSourc that’s pre-populated.

DataTable dt = new DataTable();

dt.Columns.Add(“MyNavigateUrl”, typeof(string));

dt.Columns.Add(“MyImageUrl”, typeof(string));

dt.Columns.Add(“MyText”, typeof(string));

dt.Columns.Add(“MyAlignRight”, typeof(bool));

 

dt.Rows.Add(“Default.aspx”, “VistaMenuBar/mona.gif”,

“Home”, false);

dt.Rows.Add(“Default.aspx”, “VistaMenuBar/chart.gif”,

“Add a Chart”, false);

dt.Rows.Add(“Default.aspx”, “VistaMenuBar/sos.gif”,

“Get Help”, false);

dt.Rows.Add(“Default.aspx”, “VistaMenuBar/mail.gif”,

“Send Email”, false);

 

VistaMenuBar1.DataSource = dt;

VistaMenuBar1.NavigateUrl = “MyNavigateUrl”;

VistaMenuBar1.ImageUrl = “MyImageUrl”;

VistaMenuBar1.Text = “MyText”;

VistaMenuBar1.AlignRight = “MyAlignRight”;

VistaMenuBar1.DataBind();

Vista Menu Example

We can also use the list of VistaMenuItems and bypass setting those properties.  It’s up to you!

 

List<VistaMenuItem> menuItems = new List<VistaMenuItem>();

menuItems.Add(new VistaMenuItem(“Add Record”,

“VistaMenuBar/add.gif”, “#”, false));

menuItems.Add(new VistaMenuItem(“Run Report”,

“VistaMenuBar/chart.gif”, “#”, false));

menuItems.Add(new VistaMenuItem(“Alert Admin”,

“VistaMenuBar/sos.gif”, “#”, false));

menuItems.Add(new VistaMenuItem(“Email Admin”,

“VistaMenuBar/mail.gif”, “#”, true));

 

VistaMenuBar2.DataSource = menuItems;

VistaMenuBar2.DataBind();

Download Control (v3.5) | Download Control (v2.0)

 

kick it on DotNetKicks.com 

About these ads
  1. math84
    March 4, 2008 at 10:02 am | #1

    the article is very good, but i cannot access to download the files, can you give me another link???

  2. February 28, 2009 at 9:58 pm | #2

    The should cheap car insurance quotes round lake beach .compare auto insurance as a result of car insurance online compare cheap car insurance online washington ,may be cheap health insurance
    Come to Usualy palm bay insurance for car In stuff a auto insurance .outside cheapest cost for car insurance online auto insurance quotes .

  3. May 17, 2009 at 2:45 am | #3

    Hello, Very nice site. Universe help us, dont worry man.

  4. June 11, 2009 at 11:48 am | #4

    dsfsdfs67877 test test

Comments are closed.
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: