Controlar Menus visiveis com o web.sitemap

Uma maneira rápida de ter um menu a funcionar no nosso website, é recorrer ao controlo Menu e associá-lo a um web.sitemap usando o SiteMapDataSource.

Exemplo do ficheiro web.sitemap:

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode  url="~/" title="Home"  description="Home" >
        <siteMapNode url="" description="Menu 1" title="Menu 1">
            <siteMapNode url="" description="SubMenu 1" title="Sub Menu 1"/>
        </siteMapNode>
        <siteMapNode url="" description="Menu 2" title="Menu 2"/>
        <siteMapNode url="" description="Menu 3" title="Menu 3"/>
    </siteMapNode>
</siteMap>

Exemplo do código para adicionar na página o menu:

<asp:Menu ID="NavigationMenu" runat="server" CssClass="menu" 
    EnableViewState="False" IncludeStyleBlock="False" Orientation="Horizontal" 
    DataSourceID="SiteMapDataSource1" onmenuitemdatabound="NavigationMenu_MenuItemDataBound">
</asp:Menu>
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server"  ShowStartingNode="false" />

Correndo a aplicação, iremos ter algo como a próxima imagem:

Para mostrar ou esconder os menus, consoante o tipo de acesso de cada utilizador, podemos definir as Roles em cada SiteMapNode.

Outra forma de controlar os menus visiveis, é adicionar um atributo em cada SiteMapNode e consoante o seu valor, irá ou não mostrar cada um dos menus.

Para isso, o web.sitemap será algo como:


<?xml version="1.0" encoding="utf-8"?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">
  <siteMapNode url="~/" title="Home" description="Home" visible="true">
    <siteMapNode url="" description="Menu 1" title="Menu 1" visible="true">
      <siteMapNode url="" description="SubMenu 1" title="Sub Menu 1" visible="true" />
    </siteMapNode>
    <siteMapNode url="" description="Menu 2" title="Menu 2" visible="False" />
    <siteMapNode url="" description="Menu 3" title="Menu 3" visible="true" />
  </siteMapNode>
</siteMap>

O atributo “visible” é que nos vai indicar se o menu é ou não mostrado, e para isso vamos adicionar ao evento MenuItemDataBound do Menu o seguinte código:


protected void NavigationMenu_MenuItemDataBound(object sender, MenuEventArgs e)
{
    SiteMapNode node = e.Item.DataItem as SiteMapNode;
    if (!string.IsNullOrEmpty(node["visible"]))
    {
        bool isVisible;
        if (bool.TryParse(node["visible"], out isVisible))
        {
            if (!isVisible)
            {
                if (e.Item.Parent != null)
                    e.Item.Parent.ChildItems.Remove(e.Item);
                else
                    ((Menu)sender).Items.Remove(e.Item);
            }
        }
    }
}

Desta forma, teremos o nosso menu a mostrar todos os nós cujo valor do atributo Visible seja igual a True.

Para podermos controlar directamente os menus que irão estar ou não visiveis, utilizei uma Treeview para carregar o ficheiro web.sitemap, definir que todos os items mostrarão uma checkbox, que irá indicar o estado do atributo Visible.


<asp:TreeView runat="server" ID="tvMenus" AutoGenerateDataBindings="False" DataSourceID="XmlDsSiteMap"
    OnTreeNodeCheckChanged="tvMenus_TreeNodeCheckChanged" ShowCheckBoxes="All" ShowLines="True"
    OnTreeNodeDataBound="tvMenus_TreeNodeDataBound">
    <DataBindings>
        <asp:TreeNodeBinding DataMember="siteMapNode" SelectAction="None" ShowCheckBox="True"
            TextField="title" />
        <asp:TreeNodeBinding DataMember="siteMapNode" TextField="title" />
        <asp:TreeNodeBinding DataMember="siteMapNode" TextField="title" />
        <asp:TreeNodeBinding DataMember="siteMap" />
    </DataBindings>
</asp:TreeView>
<asp:XmlDataSource ID="XmlDsSiteMap" runat="server" DataFile="~/Web.sitemap" XPath="/*/*/*">
</asp:XmlDataSource>
    <p>
        <asp:Button runat="server" ID="btn" Text="gravar" OnClick="btn_Click" /></p>

 


protected void tvMenus_TreeNodeDataBound(object sender, TreeNodeEventArgs e)
{
    XmlElement node = e.Node.DataItem as XmlElement;
    if (node.Attributes["visible"] != null)
    {
        if (!string.IsNullOrEmpty(node.Attributes["visible"].Value))
        {
            bool isVisible;
            if (bool.TryParse(node.Attributes["visible"].Value, out isVisible))
            {
                e.Node.Checked = isVisible;
            }
            else
                e.Node.Checked = true;
        }
        else
            e.Node.Checked = true;
    }
}

Por fim, para gravarmos as alterações do atributo consoante o estado da checkbox, adicionamos ao evento TreeNodeCheckChanged da Treeview o seguinte código:


protected void tvMenus_TreeNodeCheckChanged(object sender, TreeNodeEventArgs e)
{
    XmlDsSiteMap.GetXmlDocument().SelectSingleNode(e.Node.DataPath).Attributes["visible"].Value = e.Node.Checked.ToString();
}

E ao botão que adicionamos para gravar as alterações o seguinte código:


protected void btn_Click(object sender, EventArgs e)
{
    XmlDsSiteMap.Save();
}

Agora é só activar e desactivar os items ao nosso gosto.