Tales from the Evil Empire

Bertrand Le Roy's blog

News

Ads Via DevMavens

ASP.NET AJAX UpdatePanel Control: Add Ajax interactivity to your ASP.NET 2.0 web pages


follow bleroy at http://twitter.com


Add to Technorati Favorites

Blogs I read

My other stuff

SiteMap menu with icons

While binding a Menu (or TreeView: everything in this article applies to TreeView as well) to a SiteMapDataSource is very easy, it can prove challenging to find how to extend the site map with custom properties and use these extended properties in a Menu. This sample shows how to add icons in a sitemap-driven menu.

SiteMap allows the addition of custom attributes to your site map nodes. If you're using the XML site map provider, it's as simple as this:

<siteMapNode url="default.aspx" title="Home"  description="The home page" imageUrl="home.gif">

Here, imageUrl is a custom property, not defined by the SiteMap infrastructure by default.

The first idea that comes to mind to use these custom attributes is to just replace the automatic bindings you get from binding a Menu to SiteMapDataSource with "manual" bindings. This works very well with XmlDataSource because it is implemented so that the nodes implement ICustomTypeDescriptor, so any XML attribute is exposed as a property on the node as far as reflection is concerned. This is a very powerful feature of .NET reflection that gives it some of the qualities of dynamic languages. Unfortunately, SiteMapDataSource does not implement this, nor does Menu know how to query custom site map attributes. This is an oversight and we may add that support in future releases.

An easy (although not declarative) way out of this problem is to hook the OnMenuItemDataBound event and to set the custom properties from there:

public void OnItemBound(object sender, MenuEventArgs args) {
    args.Item.ImageUrl = ((SiteMapNode)args.Item.DataItem)["imageUrl"];
}

I hope this helps.

Here's a link to the full source code for this sample:
http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=61b73f00-1062-45a6-bd76-4df7cad7b028

Comments

TrackBack said:

His post contains link to interesting and related samples.
# January 24, 2006 5:41 PM

Andres said:

Thanks for this tip! I was looking exactly that.
# July 23, 2006 2:28 AM

Donna Leathers said:

Is there a way to implement background imagery with this method? Tried BackImage with no success. Ideas? Thanks!

# March 30, 2007 3:33 PM

Bertrand Le Roy said:

Donna: what BackImage are you referring to? If you want different background images for each menu item, I think you're out of luck, sorry.

# March 30, 2007 5:39 PM

Neil said:

thanks for the post - menu's now look great
# May 31, 2007 6:26 PM

Peter Goddard said:

For background image try setting a custom attribute to reflect the css class for the menu item and set the background in a stylesheet.

# June 28, 2007 3:36 AM

Bertrand Le Roy said:

Peter: the problem is that there isn't an individual css class for each menu item, so this will work for a category of items, but not for different backgrounds for each item.

# June 28, 2007 2:22 PM

AdmiralGanja said:

No sample up and running?

# July 10, 2007 8:21 AM

Bertrand Le Roy said:

AdmiralGanja: sorry, no.

# July 10, 2007 1:42 PM

Mark said:

Great, works well!

Is it possible to put spaces between the icon and the text?

# July 18, 2007 5:39 AM

Bertrand Le Roy said:

Mark: you should be able to do that with CSS. For example if the CSS class for your menu item is "foo", styling "foo img" with some right padding should do the trick.

# July 18, 2007 2:31 PM

Mark said:

How can I set a cssclass for an image?

The only classes I can set at the moment are:

<StaticMenuStyle />

<StaticMenuItemStyle CssClass="menuRootPanelItem" />

<statichoverstyle CssClass="menuRootPanelItem_Hover" />

<StaticSelectedStyle />                           <DynamicMenuStyle CssClass="menuRootPanelItem_Expanded" />

<DynamicMenuItemStyle CssClass="menuPanelItem" />

<DynamicHoverStyle CssClass="menuPanelItem_Hover" />

<DynamicSelectedStyle />

# July 19, 2007 3:35 AM

Mark said:

The following code worked but it's not the most practical.

<siteMapNode url="site.aspx" title="&amp;nbsp;&amp;nbsp;&amp;nbsp;Site" ... />

# July 19, 2007 6:56 AM

Bertrand Le Roy said:

Mark: you do it in the style sheet. Your MenuItemStyle points to menuRootPanelItem, but you can define a ".menuRootPanelItem img" style in your stylesheet which will only affect images that are inside an element with class menuRootPanelItem. Does that make sense?

# July 19, 2007 12:15 PM

Mark said:

Thanks, I understand how css works but it doesn't seem to recognise "img" for any cssClass even if I put ".img" or "imgUrl" or ".imgUrl".

Do I need to define "img" somewhere?

# July 20, 2007 11:12 AM

Bertrand Le Roy said:

Mark: I just checked, and it works great. In the stylesheet, I have:

.item img {padding-right: 50px;}

and the item style is <StaticMenuItemStyle CssClass="Item"/>

# July 20, 2007 2:10 PM

lance said:

How would I access a Treeview node so that I could set individual css classes based on .sitemap attributes? For example:

<siteMapNode title="Our Services" url="~/Services/Default.aspx" description="Our Services" cssclass="gnav"></siteMapNode>

public void OnTreeViewDataBound(object sender, MenuEventArgs args) {

   ??????????????

}

# July 20, 2007 4:02 PM

Bertrand Le Roy said:

Lance: you can't, sorry.

# July 20, 2007 4:43 PM

Mark said:

No worries, I've got it working now.

I wasn't setting an img class for both StaticMenuItemStyle AND DynamicMenuItemStyle as they use different cssClasses.

Thanks for your help.

# July 26, 2007 8:35 AM

Don Irwin said:

Great post Bertrand.  Know of any way to change the image on hover?  Say a grayscale image until the user hovers over an icon and then diplay the same image in color.

# December 6, 2007 9:21 PM

cxspan said:

Freakin' sweet! (Peter Griffin voice)

This is just what I needed to figure out how to *remove* Menu items programmatically.  I couldn't just remove them from my sitemap b/c I still wanted them to show up in the breadcrumbs (don't ask).  I added a "hideOnMenu" property to the sitemapnodes I wanted hidden and set it to true.

Then, in the MenuItemDataBound event I added the following:

MenuItem parent = e.Item.Parent;

string hideOnMenu = ((SiteMapNode)e.Item.DataItem)["hideOnMenu"];

       if (hideOnMenu != null)

       {

           if (bool.Parse(hideOnMenu))

           {

               parent.ChildItems.Remove(e.Item);

           }

       }

I don't know if this is the best solution, but it's working great for me!!

# January 11, 2008 3:34 PM

cxspan said:

errr... slight modification to work with top-level menu items:

string hideOnMenu = ((SiteMapNode)e.Item.DataItem)["hideOnMenu"];

       if (hideOnMenu != null && bool.Parse(hideOnMenu))

       {

               MenuItem parent = e.Item.Parent;

               if (parent != null) parent.ChildItems.Remove(e.Item);

               else (sender as Menu).Items.Remove(e.Item);

       }

# January 11, 2008 3:51 PM

Bikaram said:

Thanks This was very useful to me

# April 18, 2008 9:11 PM

Omego2K said:

but since a Menu control doesn't understand the imageURL property, how do you get it to display the image?

# July 16, 2008 6:37 PM

Bertrand Le Roy said:

# July 16, 2008 6:43 PM

exz said:

thanks, just what I was looking for.

# July 24, 2008 4:01 AM

celik said:

Thanks, very helpful

# September 18, 2008 8:09 PM

anie said:

Hi Bertrand, need help on this.

I'm new in this kind of stuff, and I'm trying to have image buttons instead of text in the sitemap. I'm using web.sitemap file from ASP.Net. Then I specified this in my masterpage:

<asp:Menu ID="Menu1" Runat="server" DataSourceID="SiteMapDataSource1" Target ="_blank" Orientation="Horizontal" StaticDisplayLevels="2" DynamicEnableDefaultPopOutImage="false" StaticEnableDefaultPopOutImage ="false"></asp:Menu>

And add some coding part as you said in the article.

But it still return text-sitemap, not image sitemap the way I want. Is there anything I should add or something?

# November 26, 2008 5:05 AM

anie said:

Hi Bertrand, just found out why it didn't work out. My mistake, my asp:menu tag was not complete. It runs well now, Thanks..

# November 26, 2008 8:13 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)