Jeff Cleath

Technology Management

Adding MouseOver Images to the ASP.NET 2.0 Menu Control

 

When using the ASP.NET 2.0 Menu control I was surprised to find that it did not support an image mouseover event to swap images.   After doing a Google search and finding the post by Stephen Page at http://www.velocityreviews.com/forums/t117199-menu-control-aspnet-20.html I was able to use his example and develop the following code to implement the functionality.  I added the custom attributes of ImageUrl and AltImageUrl to the sitemap file and then used the following ItemDataBound event on the menu control.

protected void _siteMenu_ItemDataBound(object sender, System.Web.UI.WebControls.MenuEventArgs e)

{

// Reference the underlying SiteMapNode object...
MenuItem item = (MenuItem)e.Item;
SiteMapNode nodeFromSiteMap = (SiteMapNode)e.Item.DataItem;

string onImage = "";
string offImage = "";
string navUrl = "";

// If we have an imageUrl value, assign it to the menu node's ImageUrl property
if (nodeFromSiteMap["imageUrl"] != null)
{
onImage = System.Web.
HttpContext.Current.Request.ApplicationPath + System.IO.Path.Combine("/Images/Elements/", nodeFromSiteMap["imageUrl"]);
offImage = System.Web.
HttpContext.Current.Request.ApplicationPath + System.IO.Path.Combine("/Images/Elements/", nodeFromSiteMap["altImageUrl"]);
}
navUrl = nodeFromSiteMap[
"url"];

// These objects are necessary in order to capture the image object into a rendered html format
string src = offImage;
string toolTip = "";
System.Text.
StringBuilder sb = new System.Text.StringBuilder();
System.IO.
StringWriter sw = new System.IO.StringWriter();
HtmlTextWriter htmWriter = new HtmlTextWriter(sw);
HtmlImage image = new HtmlImage();

image.Style.Add("border-style", "none");
MenuItem theMenuButton = new MenuItem();
theMenuButton.NavigateUrl = navUrl;
image.Src = src;

if (onImage != "" && onImage != null)
image.Attributes[
"onMouseOver"] = "this.src='" + onImage + "';";
if (onImage != "" && onImage != null)
image.Attributes[
"onMouseDown"] = "this.src='" + onImage + "';";
image.Attributes[
"onMouseOut"] = "this.src='" + offImage + "';";
image.RenderControl(htmWriter);
item.Text = sw.ToString();
}

If anyone else has other options I would be glad to hear back from you. 

Comments

oooshola said:

This seems like a pretty clean way to do it. However, I can no longer see my dynamic menu items appear and disappear. Did i do something wrong?

# June 14, 2007 10:18 AM

Vimal said:

Hi,

I am also in need of such a component. Let me try this

# November 5, 2007 11:53 PM

sulfur_scratch said:

Could this have not been achieved using CSS?

# December 20, 2007 4:20 PM

colin said:

My images are broken when i mouseover them is there any code missing that i should put in the front end?? Also in order not to get an error on my page node["AltImg"] != null in first if statement

# March 19, 2008 10:16 AM

Russ Morlando said:

Hope this isn't a dead thread.  A little tweaking during conversion to VB.net and it worked like a charm.  Thanks for a simple solution.

# July 11, 2008 10:29 PM

ash143gupta said:

Hi i have applied and tested your code but everything is working fine but my text is not coming from my sitemap file. Although it is navigating but still the text is not displaying and if it does not than all this hardwork is a waste because than i could use simple links and images to achieve this do we have a workaround or i am missing something, i am a vb.net developer and just translated your code to vb.net and added one or two new things but text is not displaying.

Please help

# July 13, 2008 5:07 PM

N said:

Hi, Im relatively new to ASP.NET and had an attempt with your example. I can get images for the menu items when the page first loads. These images reference the altImageUrl defined in the websitemap. Unfortunately on mouse over the images are lost.  Am I missing detail for: image.Src = src;

if (onImage != "" && onImage != null)

image.Attributes["onMouseOver"] = "this.src='" + onImage + "';";

Was also wondering if your example can include an image for the selected (active) menu item.   Thanks  

# July 18, 2008 2:02 AM

Justin said:

I'm trying to implmenet this code and I get the following error:

CS0123: No overload for '_siteMenu_ItemDataBound' matches delegate 'System.EventHandler'

my menu control on the aspx page:

<asp:Menu OnDataBound="_siteMenu_ItemDataBound" ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" />

Any Ideas?

# August 28, 2008 4:20 AM

Justin said:

I found the answer! Hope this help's someone else.

Intellisence wasn't picking up the "onmenuitemdatabound" in the control.

Resolved by updating the following:

<asp:Menu  onmenuitemdatabound="_siteMenu_ItemDataBound" ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" />

# August 28, 2008 4:28 AM

Justin said:

I found that this works fine when I'm using VS's development enviroment, but the images didn't display when I was using IIS.

I have updated the code to do the follow:

1. Display images when using IIS or VS ASP.NET Web SVR (Full url reqired in web.sitemap) e.g:

<siteMapNode url="~/Default.aspx" title="Home" imageUrl="images/buttons/home_ov.jpg" altImageUrl="images/buttons/home_up.jpg" "/>

2. Display "up" or "on" images when pages is selected.

protected void _siteMenu_ItemDataBound(object sender, System.Web.UI.WebControls.MenuEventArgs e)

   {

       // Reference the underlying SiteMapNode object...

       MenuItem item = (MenuItem)e.Item;

       SiteMapNode nodeFromSiteMap = (SiteMapNode)e.Item.DataItem;

       string onImage = "";

       string offImage = "";

       string navUrl = "";

       // If we have an imageUrl value, assign it to the menu node's ImageUrl property

       if (nodeFromSiteMap["imageUrl"] != null)

       {

           //onImage =  System.Web.HttpContext.Current.Request.ApplicationPath + System.IO.Path.Combine("~/Images/Buttons/", nodeFromSiteMap["imageUrl"]);

           //offImage = System.Web.HttpContext.Current.Request.ApplicationPath + System.IO.Path.Combine("~/Images/Buttons/", nodeFromSiteMap["altImageUrl"]);

           onImage = Page.ResolveUrl("~") + nodeFromSiteMap["imageUrl"];

           offImage = Page.ResolveUrl("~") + nodeFromSiteMap["altImageUrl"];

       }

       navUrl = nodeFromSiteMap["url"];

       // These objects are necessary in order to capture the image object into a rendered html format

       string src = offImage;

       // If item selected, show onImage

       if (item.Selected)

       { src = onImage; }

       string toolTip = "";

       System.Text.StringBuilder sb = new System.Text.StringBuilder();

       System.IO.StringWriter sw = new System.IO.StringWriter();

       HtmlTextWriter htmWriter = new HtmlTextWriter(sw);

       HtmlImage image = new HtmlImage();

       image.Style.Add("border-style", "none");

       MenuItem theMenuButton = new MenuItem();

       theMenuButton.NavigateUrl = navUrl;

       image.Src = src;

       if (onImage != "" && onImage != null)

           image.Attributes["onMouseOver"] = "this.src='" + onImage + "';";

       if (onImage != "" && onImage != null)

           image.Attributes["onMouseDown"] = "this.src='" + onImage + "';";

       image.Attributes["onMouseOut"] = "this.src='" + src + "';";

           image.RenderControl(htmWriter);

       item.Text = sw.ToString();

   }

again, hope someone finds this usefull.

# August 28, 2008 7:26 AM

RykAns said:

Justin...tnx very much for your codes...im hapi that i discovered these codes on menu manipulation on images... b4 i used css and linkbutton for my menu items just to get my mouse hover changes on image...but my senior didnt allow me to use linkbutton...tnx very much u saved me...God Bless...

# October 22, 2008 10:18 PM

Newbie-girl said:

It works fine for me, BUT, how do I get the image selected while the URL (the selected page) is active?

Thanx

# January 23, 2009 9:03 AM

Newbie-girl said:

Sorry, please discard my previous comment, I found the solution from Justin above. Thanx!

# January 23, 2009 9:08 AM

Jaime Weise said:

class='<%# Boolean.Parse(Eval("Selected").ToString())? "menuselected": "menu" %>'

# February 20, 2009 3:02 AM

Jaime Weise said:

class='<%# Boolean.Parse(Eval("Selected").ToString())? "menuselected": "menu" %>'

# February 20, 2009 3:02 AM

Jaime said:

or to be more precise

           <StaticItemTemplate>

               <div id="Item1" runat="server"

                    class='<%# Boolean.Parse(Eval("Selected").ToString())? "menuselected": "menu" %>'

                    ie:style="margin-top: -1px;">

                   <asp:Label CssClass="menuitemtext" ID="label2" Text='<%# Eval("Text") %>'

                       runat="server" /></div>

           </StaticItemTemplate>

   .menu, .menu:hover

   {

       border: 0px;

       float: left;

       padding: 0px 10px;

       z-index: 1;

       height: 46px;

       background-image: url(menu.png);

       background-repeat: repeat-x;

       color: white;

       font-size: 12pt;

       font-weight: bold;

       text-decoration: none;

       cursor: pointer;

   }

   .menu:hover, .menuselected:hover

   {

       color: #2085B1;

       background-image: url(menu_over.png);

       background-position: 0px;

   }

   .menuselected, .menuselected:hover

   {

       border: 0px;

       float: left;

       padding: 0px 10px;

       z-index: 1;

       height: 45px;

       background-image: url(menu_over.png);

       background-repeat: repeat-x;

       color: #2085B1;

       font-size: 12pt;

       font-weight: bold;

       text-decoration: none;

       cursor: pointer;

   }

# February 20, 2009 3:05 AM

jwize said:

This works for me

// Menu template code.

<StaticItemTemplate>

               <div id="Item1" runat="server"

                    class='<%# Boolean.Parse(Eval("Selected").ToString())? "menuselected": "menu" %>'

                    ie:style="margin-top: -1px;">

                   <asp:Label CssClass="menuitemtext" ID="label2" Text='<%# Eval("Text") %>'

                       runat="server" /></div>

           </StaticItemTemplate>

// You just need code that can figure out what the selected page might be in the MenuItemDataBound and set the selected property to true.

  protected void Menu1_MenuItemDataBound(object sender, MenuEventArgs e)

   {

       if (Page.Request.Url.AbsolutePath.ToUpper().EndsWith(String.Format("{0}{1}", e.Item.Text, ".aspx").ToUpper()))

       {

           e.Item.Selected = true;

       }

   }

finally some styles to show the correct image.

   .menu, .menu:hover

   {

       background-image: url(menu.png);

       background-repeat: repeat-x;

   }

   .menu:hover, .menuselected:hover

   {

       background-image: url(menu_over.png);

       background-position: 0px;

   }

   .menuselected, .menuselected:hover

   {

       background-image: url(menu_over.png);

       background-repeat: repeat-x;

       }

# February 21, 2009 3:56 PM