Archive

Archive for the ‘XML’ Category

How to combine two asp.net Menu Controls with single site map and populate second menu based on first menu selection


To handle multiple asp.net menu controls based on single site map data source:

  1. Convert all the links of the first menu to perform a postback instead of rendering as links.
  2. Use a hidden variable and __MENUTARGET and hidden button __BTNHELPER
  3. Use javascript to postback the page using __BTNHELPER.
  4. In the code behind (usually in the master page) handle button event and read the site map in to XPathDocuemnt, create navigator and perform a XPath query for the relevent node
  5. Populate the second menu with the selected XML node
  6. Use an recursive method to populate all the child menu items
  7. In this article I have not used a application variable, but it is better to hold the Web.sitemap file (XPathNavigator) instead of reading on each menu click.
  8. I have used empty namespace, but if you use a namespace (usually sitemap file comes with a namespace) you have to change to XPath logoc accordingly.

Site.Master page:

<%@ Master Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head runat="server">
    <title></title>
    <script language="javascript" type="text/javascript">
    </script>
    <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
    <script runat="server">
        private string script = @"
            function __doPopulateMenu(target) {{
                document.getElementById(""{0}"").value = target;
                __doPostBack(""{1}"", """");
            }}
        ";
        protected void Page_Load(object sender, EventArgs e)
        {
 
        }
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            this.Page.ClientScript.RegisterClientScriptBlock(
                this.GetType(), this.GetType().Name,
                string.Format(this.script,
                this.__MENUTARGET.ClientID,
                this.__BTNHELPER.UniqueID), true);
        }
        public string GetUrl(object target)
        {
            return string.Format("javascript:__doPopulateMenu(\"{0}\")", target);
        }
        protected void PopulateLeftNagivation(object sender, EventArgs e)
        {
            this.mnuLeftNavigation.Items.Clear();
            XPathDocument doc = new XPathDocument(Server.MapPath("~/Web.sitemap"));
            XPathNavigator navigator = doc.CreateNavigator();
            XPathNodeIterator reader = navigator.Select(
                string.Format("/siteMap/siteMapNode[@url='']/siteMapNode[@url='{0}']/siteMapNode", 
                Path.GetFileName(this.__MENUTARGET.Value)));
            this.BuildLeftMenu(this.mnuLeftNavigation.Items, reader);
        }
        private void BuildLeftMenu(MenuItemCollection items, XPathNodeIterator reader)
        {
            while (reader.MoveNext())
            {
                MenuItem item = new MenuItem(reader.Current.GetAttribute("url"string.Empty), 
                    reader.Current.GetAttribute("title"string.Empty));
                items.Add(item);
                if (reader.Current.HasChildren)
                    this.BuildLeftMenu(item.ChildItems, 
                        reader.Current.SelectChildren("siteMapNode"string.Empty));
            }
        }        
    </script>
    <asp:ContentPlaceHolder ID="HeadContent" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form runat="server">
    <asp:ScriptManager runat="server" ID="ScriptManager1"></asp:ScriptManager>
    <div class="page">
        <div class="main">
            <asp:UpdatePanel runat="server" ID="upnlNavigation">
                <ContentTemplate>
                    <div class="NavigationWrapper">
                        <div class="TopNanvigation">
                            <asp:SiteMapDataSource runat="server" ID="SiteMapDataSource" 
                                ShowStartingNode="false" />
                            <asp:Menu 
                                runat="server" 
                                ID="mnuTopNavigation" 
                                Orientation="Horizontal" 
                                DataSourceID="SiteMapDataSource" 
                                StaticDisplayLevels="1" 
                                MaximumDynamicDisplayLevels="0">
                                <StaticItemTemplate>
                                    <a href='<%# this.GetUrl(Eval("NavigateUrl")) %>'><%# Eval("Text"%></a>
                                </StaticItemTemplate>
                            </asp:Menu>
                        </div>
                        <div class="LeftNavigation">
                            <asp:Menu runat="server" ID="mnuLeftNavigation" />
                        </div>
                    </div>
                    <asp:Button runat="server" ID="__BTNHELPER" OnClick="PopulateLeftNagivation"
                        UseSubmitBehavior="false" style="display:none" />
                    <asp:HiddenField runat="server" ID="__MENUTARGET" />
                </ContentTemplate>
            </asp:UpdatePanel>
            <div class="MainContent">
                <asp:ContentPlaceHolder ID="MainContent" runat="server"/>
            </div>
        </div>
        <div class="clear">
        </div>
    </div>
    <div class="footer">
        
    </div>
    </form>
</body>
</html>

Web.sitemap file (please not no name space)

<?xml version="1.0" encoding="utf-8" ?>
<siteMap>
    <siteMapNode url="" title=""  description="">
      <siteMapNode url="Page1.aspx" title="Item 1"  description="">
        <siteMapNode url="SubPage11.aspx" title="Sub Item 11" />
        <siteMapNode url="SubPage12.aspx" title="Sub Item 12" >
          <siteMapNode url="SubPage121.aspx" title="Sub Item 121" />
          <siteMapNode url="SubPage122.aspx" title="Sub Item 122" />
          <siteMapNode url="SubPage123.aspx" title="Sub Item 123" />
        </siteMapNode>
        <siteMapNode url="SubPage13.aspx" title="Sub Item 13" />
        <siteMapNode url="SubPage14.aspx" title="Sub Item 14" />
        <siteMapNode url="SubPage15.aspx" title="Sub Item 15" />
      </siteMapNode>
      <siteMapNode url="Page2.aspx" title="Item 2"  description="">
        <siteMapNode url="SubPage21.aspx" title="Sub Item 21" />
        <siteMapNode url="SubPage22.aspx" title="Sub Item 22" />
        <siteMapNode url="SubPage23.aspx" title="Sub Item 23" />
      </siteMapNode>
      <siteMapNode url="Page3.aspx" title="Item 3"  description="">
        <siteMapNode url="SubPage31.aspx" title="Sub Item 31" />
        <siteMapNode url="SubPage32.aspx" title="Sub Item 32" />
        <siteMapNode url="SubPage33.aspx" title="Sub Item 33" />
        <siteMapNode url="SubPage34.aspx" title="Sub Item 34" />
      </siteMapNode>
      <siteMapNode url="Page4.aspx" title="Item 3"  description="">
        <siteMapNode url="SubPage41.aspx" title="Sub Item 41" />
        <siteMapNode url="SubPage42.aspx" title="Sub Item 42" />
      </siteMapNode>
      <siteMapNode url="Page5.aspx" title="Item 3"  description="">
        <siteMapNode url="SubPage51.aspx" title="Sub Item 51" />
        <siteMapNode url="SubPage52.aspx" title="Sub Item 52" />
        <siteMapNode url="SubPage53.aspx" title="Sub Item 53" />
        <siteMapNode url="SubPage54.aspx" title="Sub Item 54" />
      </siteMapNode>
    </siteMapNode>
</siteMap>
Categories: Asp.net, C#, XML Tags: , ,