SiteMenu Builder

SiteMenu Builder

Posted on February 13, 2010 0 Comments

The content you're reading is getting on in years
This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.

This post will show you how to create custom navigation menu for your website, where you can specify which pages you want to see and which not. There are many cases where you want to have two level navigation or several navigational  menus. Each time you will have to do some coding over the menu so that it will start showing the appropriate items/nodes.

In this post I am creating a custom class that inherits from WebUITypeEditor.

First I am going to build WebUITypeEditor using RadTreeView control which supports multiple selection. This seems to be the most appropriate control to achieve my goal. I will bind the control to a list containing all pages by using the CmsManager.GetPages() method. Then I will return the ID of each node to my property as a Guid array.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Telerik.Cms.Web.UI;
using Telerik.Web.UI;
using Telerik.Framework.Web;
using Telerik.Cms;
using System.Collections;
using System.Web.UI;
using Telerik.Cms.Web;
 
/// <summary>
/// Summary description for DynamicMenuBuilderWebUITypeEditor
/// </summary>
public class DynamicMenuBuilderWebUITypeEditor : WebUITypeEditor<Guid[]>
{
    public DynamicMenuBuilderWebUITypeEditor()
    {
 
    }
 
    public override Guid[] Value
    {
        get
        {
            Guid pageId = Guid.Empty;
            List<Guid> selectedIds = new List<Guid>();
            foreach (RadTreeNode node in TreeView.SelectedNodes)
            {
                if (node != null)
                {
                    CmsSiteMapNode smNode = (CmsSiteMapNode)SiteMap.Provider.FindSiteMapNode("~/" + node.FullPath + ".aspx");
                    ICmsPage cmsPage = manager.GetPage(smNode.CmsPage.ID) as ICmsPage;
                    pageId = cmsPage.ID;
                    selectedIds.Add(pageId);
                }
            }
            return selectedIds.ToArray();
        }
        set
        {
            this.ViewState["selectedPage"] = value;
            base.ChildControlsCreated = false;
        }
    }
 
    public string Templte
    {
        get
        {
            object o = this.ViewState["Template"];
            if (o == null)
                return ("~/CustomControls/PageIDWebEditor.ascx");
            return (string)o;
        }
        set
        {
            this.ViewState["Template"] = value;
        }
    }
    
 
    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        this.manager = new CmsManager();
        this.template = ControlUtils.GetTemplate<SelectorTemplate>(this.Templte);
        this.template.InstantiateIn(this);
        var manager = new CmsManager();
        IList allPages = manager.GetPages();
        TreeView.MultipleSelect = true;
        TreeView.DataSource = allPages;
        TreeView.DataTextField = "MenuName";
        TreeView.DataFieldParentID = "ParentID";
        TreeView.DataFieldID = "ID";
        TreeView.DataNavigateUrlField = "StaticUrl";
        TreeView.DataBind();
    }
 
    protected virtual RadTreeView TreeView
    {
        get
        {
            return this.Controls[0].FindControl("RadTreeView1") as RadTreeView;
        }
    }
 
    public class SelectorTemplate : ITemplate
    {
        public void InstantiateIn(Control container)
        {
        }
    }
 
    private ITemplate template;
    private CmsManager manager;
 
}

My Selector template is shown below. I declared there a RadTreeView instance:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="PageIDWebEditor.ascx.cs" Inherits="CustomControls_PageIDWebEditor" %>
 
 
<asp:Label runat="server" ID="Label1" Text="Select a page from the tree" />
<telerik:RadTreeView ID="RadTreeView1" runat="server" Skin="Black"/>

In the code behind I have to disable the NavigateUrl as otherwise when a node is selected a postback will appear, which will clear the selected nodes collection.

public partial class CustomControls_PageIDWebEditor : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        RadTreeView1.NodeDataBound += new Telerik.Web.UI.RadTreeViewEventHandler(RadTeerView1_NodeDataBound);
    }
 
    void RadTeerView1_NodeDataBound(object sender, Telerik.Web.UI.RadTreeNodeEventArgs e)
    {
        foreach (RadTreeNode node in RadTreeView1.GetAllNodes())
        {
            node.NavigateUrl = "";
        }
    }
}

My selector is ready and now I need a custom control. The custom control will inherit from the well know CompositeControl class. This custom control does not need a template, because the SiteMenu will be dynamically generated.

I need a ViewState property from where I will call the WebUITypeEditor. I will use the built-in GuidArrayConverter, so that I will not have to create a custom DictionaryConverter for my property that is not just a simple string

[WebEditor("DynamicMenuBuilderWebUITypeEditor, App_Code")]
    [TypeConverter("Telerik.Framework.Utilities.GuidArrayConverter, Telerik.Framework")]
    public Guid[] PageIDs
    {
        get
        {
            object obj = this.ViewState["PageIDs"];
            if (obj != null)
                return (Guid[])obj;
            return new Guid[0];
             
        }
        set
        {
            this.ViewState["PageIDs"] = value;
        }
    }

I will override CreateChildControls() where I will dynamically create a RadMenu control and List of all selected pages. Then, I will bind the menu to this list similar to the way that is used in the custom selector to populate the RadTreeView control.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using Telerik.Cms.Web.UI;
using System.ComponentModel;
using Telerik.Web.UI;
using Telerik.Cms;
 
/// <summary>
/// Summary description for DynamicMenuBuilder
/// </summary>
public class DynamicMenuBuilder : CompositeControl
{
    public DynamicMenuBuilder()
    {
 
    }
 
    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        RadMenu menu = new RadMenu();
        var Manager = new CmsManager();
        List<ICmsPage> selectedPages = new List<ICmsPage>();
 
        foreach (Guid g in PageIDs)
        {
            ICmsPage p = Manager.GetPage(g, false) as ICmsPage;
            if (p != null)
            {
                selectedPages.Add(p);
            }
        }
        menu.DataSource = selectedPages;
        menu.DataTextField = "MenuName";
        menu.DataFieldParentID = "ParentID";
        menu.DataFieldID = "ID";
        menu.DataNavigateUrlField = "StaticUrl";
        menu.DataBind();
        Controls.Add(menu);
    }
 
 
    [WebEditor("DynamicMenuBuilderWebUITypeEditor, App_Code")]
    [TypeConverter("Telerik.Framework.Utilities.GuidArrayConverter, Telerik.Framework")]
    public Guid[] PageIDs
    {
        get
        {
            object obj = this.ViewState["PageIDs"];
            if (obj != null)
                return (Guid[])obj;
            return new Guid[0];
             
        }
        set
        {
            this.ViewState["PageIDs"] = value;
        }
    }
}

progress-logo

The Progress Team

View all posts from The Progress Team on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.

Comments

Comments are disabled in preview mode.
Topics

Sitefinity Training and Certification Now Available.

Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.

Learn More
Latest Stories
in Your Inbox

Subscribe to get all the news, info and tutorials you need to build better business apps and sites

Loading animation