Gorgo.Live.ToString()

Mariusz, Gorzoch tech Blog

Two tricks around ASP.NET menu stuff

leave a comment »

Today I would like to describe two tricks around menu stuff in asp.net which I was looking for a while and on the end manage to sort them out. So… let go:

1. How to extend breadcrumb menu to not only use site map xml file but also include some dynamic pages name.

Here is an example: We have our site described with site map xml file like the one shown below:

<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="~/default.aspx" title="Home"  description="Strona główna aplikacji">
      <siteMapNode url="~/Faktura/default.aspx" title="Faktury"  description="">
        <siteMapNode url="~/Faktura/Faktura.aspx?ID=0" title="Nowa faktura" description="Pozwala na wprowadzenie nowej faktury do systemu"></siteMapNode>
        <siteMapNode url="~/Faktura/Faktura.aspx" visible="false" title="Faktura" description="Pokazuje szczegóły wybranej faktury"></siteMapNode>
        <siteMapNode url="~/Faktura/ListaFaktur.aspx" title="Lista faktur" description="Prezentuje liste wszystkich faktur wprowadzonych do "></siteMapNode>
        <siteMapNode url="~/Faktura/Wyszukaj/default.aspx" title="Wyszukaj" description="Pozwala na wyszukiwanie faktur na bazie zadanych parametrów">
          <siteMapNode url="~/Faktura/Wyszukaj/MojeFaktury.aspx" title="Moje faktury" description="Prezentuje liste faktur utworzonych przez aktualnego użytkownika"></siteMapNode>
          <siteMapNode url="~/Faktura/Wyszukaj/AdvSearch.aspx" title="Wyszukiwanie zaawansowane" description=""></siteMapNode>
        </siteMapNode>
      </siteMapNode>
</siteMap>

and now … the file “/Faktura/Faktura.aspx” is responsible for presenting particular “Faktura” object based on the ID passed as a parameter. If we will go normal way and just use “SiteMapPath” control to build breadcrumb menu, then for all “Faktura” object we will get the same entry “Faktura”. To overcome this what you need is to get rid of default “SiteMapPath” and build our own one. To do so, just add “ascx” control to your project, switch to code behind and replace your code with this one:

public string CurrentItemName
{
    get
    {
        return Convert.ToString(ViewState[this.ClientID + "_curItemName"]);
    }
    set
    {
        ViewState[this.ClientID + "_curItemName"] = value;
    }
}

protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender(e);

    Stack<Control> MenuOptions = new Stack<Control>();

    SiteMapNode current = SiteMap.CurrentNode;

    if (current != null)
    {
        if (!String.IsNullOrEmpty(CurrentItemName))
            MenuOptions.Push(new LiteralControl(CurrentItemName));

        do
        {
            if (MenuOptions.Count > 0)
                MenuOptions.Push(new LiteralControl(" > "));

            HtmlAnchor anh = new HtmlAnchor();
            anh.InnerHtml = current.Title;
            anh.HRef = current.Url;
            MenuOptions.Push(anh);

            current = current.ParentNode;
        } while (current != null);

        while (MenuOptions.Count > 0)
            this.Controls.Add(MenuOptions.Pop());
    }
}

As you can see, this control is using “SiteMap” to retrieve list of nodes and extend them with additional “CurrentItemName” property. After placing this control on you master page you need to let the “layout pages” to set-up this value according to the item their presenting and DONE! Each time someone visit your “dynamic content page” he will get on the end of breadcrumb menu your object name.

2. How to hide some menu options from ASP.NET “Menu” control when he is using “SiteMapDataSource” object (created based on SiteMap, which is using XML site map file).

If you think that it is easy and logic, then go and try … to find quite soon, that you were wrong. Anyway after going thru few blogs I combined this in one peace of code and here it is :

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    //we are hooking to item databound event so we can remove unnecesary nodes
    Menu1.MenuItemDataBound += new MenuEventHandler(Menu1_MenuItemDataBound);
}

void Menu1_MenuItemDataBound(object sender, MenuEventArgs e)
{
    SiteMapNode mapNode = e.Item.DataItem as SiteMapNode;
    if (mapNode!=null)
        if (mapNode["visible"] != null && mapNode["visible"] == "false")
        {
            RemoveMenuItem(Menu1.Items,e.Item);                   
        }
}

private bool RemoveMenuItem(MenuItemCollection MenuItems,MenuItem itemToRemove)
{
    for (int i = 0; i < MenuItems.Count; i++)
        if (MenuItems[i] == itemToRemove)
        {
            MenuItems.Remove(itemToRemove);
            return true;
        }
        else
            if (RemoveMenuItem(MenuItems[i].ChildItems, itemToRemove))
                return true;
    return false;
}

So i nut shell I’m hooking to the “MenuItemDataBound” event and looking for attribute “visible” of my site node (of course this “visible” attribute need to be added to your xml site map file <- you can see how I did in on the example of this file shown on the begging of this post). As soon I found this attribute and confirm that his value is “false” then I’m looking thru all items inside Menu to find my current item and removing it from the nodes tree. This works like a charm… and “visible=’false’” nodes do not pop-up on the menu, while they still available for other “navigation” controls.

happy coddling from Igorus and his fatherus.

Advertisements

Written by Mariusz Gorzoch

26 January 2010 at 21:29

Posted in Bez kategorii

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: