Click here to Skip to main content
15,896,201 members
Articles / Web Development / HTML

Templated Hierarchical Repeater Control

Rate me:
Please Sign up or sign in to vote.
4.12/5 (10 votes)
5 Mar 2009CPOL7 min read 45.7K   1K   32  
A Templated Databound control for making TreeViews and displaying hierarchical data
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using DaveControls.HierarchicalControls.Data;
using System.Text;

namespace Samples
{
    public partial class TreeView : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // need to add the client id of the expand collapse states hidden field so that javascript can access it
            this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "expandCollapseHiddenFieldId", String.Format("var expandCollapseHiddenFieldId = '{0}';", ExpandCollapseStatesHiddenField.ClientID), true);

            if (!IsPostBack)
            {
                DataBindList();
            }
            else
            {
                // re-databind the tree view to preserve the users expand/collapse changes
                ReDataBindList();
            }
        }

        /// <summary>
        /// This method will re-data bind the tree view from the original datasource, but will keep the 
        /// item's expand and collapse states set by the user.
        /// </summary>
        private void ReDataBindList()
        {
            TreeViewTestData dataSource = TestDataSource;

            string currentExpandCollapseStates = ExpandCollapseStatesHiddenField.Value;

            int index = 0;

            SetDataSourceExpandCollapseStates(dataSource, ref index, currentExpandCollapseStates);

            TreeViewHierarchicalRepeater.DataSource = dataSource;
            TreeViewHierarchicalRepeater.DataBind();
        }

        /// <summary>
        /// This method recurses through the datasource and sets the "Expanded" property for each dataitem
        /// according the the expand/collapse states string
        /// </summary>
        /// <param name="dataSource">The datasource to recurse through</param>
        /// <param name="index">the current index of the state string representing the current tree node</param>
        /// <param name="currentExpandCollapseStates">the string representing the expand/collapse states to set</param>
        private void SetDataSourceExpandCollapseStates(TreeViewTestData dataSource, ref int index, string currentExpandCollapseStates)
        {
            for (int i = 0; i < dataSource.Count; i++)
            {
                TreeViewTestData item = (TreeViewTestData)dataSource[i];

                if (index >= currentExpandCollapseStates.Length)
                {
                    // the expand collapse states string is too short for the 
                    // amount of items in the expand string

                    throw new Exception("The ExpandCollapseState string for the treeview is too short");
                }
                else
                {
                    char c = currentExpandCollapseStates[index];
                    if (c == 'e')
                    {
                        item.Expanded = true;
                    }
                    else if (c == 'c')
                    {
                        item.Expanded = false;
                    }
                }

                index++;

                if (item.HasChildren)
                {
                    SetDataSourceExpandCollapseStates(item, ref index, currentExpandCollapseStates);
                }
            }
        }

        /// <summary>
        /// This method will databind the tree view with the item's expand/collapse states from the original
        /// datasource.  Calling this method in post back will cause the display to loose the item's expand and
        /// collapse states that have been changed by the user.
        /// </summary>
        private void DataBindList()
        {
            TreeViewHierarchicalRepeater.DataSource = TestDataSource;
            TreeViewHierarchicalRepeater.DataBind();

            // we need to load the tree view state hidden field with a string to represent the
            // required expand/collapse state of all of the treeview items.
            // By doing this, javascript will be able to access the states client side, and they
            // can be persisted accross postbacks.

            StringBuilder sb = new StringBuilder();

            // recurse through the nodes
            BuildExpandCollapseStates(TestDataSource, sb);

            // set the hidden field with the expand/collapse states string
            ExpandCollapseStatesHiddenField.Value = sb.ToString();
        }

        /// <summary>
        /// This method recursively traverses the tree view to build a string with the nodes' 
        /// expand/collapse states
        /// </summary>
        /// <param name="dataSource"></param>
        /// <param name="sb"></param>
        private void BuildExpandCollapseStates(TreeViewTestData dataSource, StringBuilder sb)
        {
            IEnumerator dataEnum = dataSource.GetEnumerator();

            while (dataEnum.MoveNext())
            {
                TreeViewTestData item = (TreeViewTestData)dataEnum.Current;

                // add "e" if the item is expanded or "c" if it is collapsed
                sb.Append(item.Expanded ? "e" : "c");

                if (item.HasChildren)
                {
                    BuildExpandCollapseStates(item, sb);
                }
            }
        }

        /// <summary>
        /// This method is called when the user clicks on an item in the control.  It locates the item from the 
        /// data source and displays its description next to the control.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void TreeViewHierarchicalRepeater_ItemCommand(object sender, DaveControls.HierarchicalControls.HierarchicalRepeaterCommandEventArgs e)
        {
            if (e.CommandName == "ClickItem")
            {
                string path = e.CommandArgument.ToString();

                HierarchyDataItemBase selectedItem = TestDataSource.GetItem(path);

                if (selectedItem != null)
                {
                    TreeViewTestData item = (TreeViewTestData)selectedItem;
                    ItemTextLiteral.Text = item.Text;
                    ItemDescriptionLiteral.Text = item.Description;

                    DescriptionPlaceholder.Visible = true;
                    NoDescriptionPlaceholder.Visible = false;
                }
            }
        }

        /// <summary>
        /// This is the data source the HierarchicalRepeater control will be data bound to.  
        /// The HierarchicalRepeater control requires its datasource object to inherit HierarchyDataItemBase
        /// </summary>
        private TreeViewTestData _testDataSource;
        private TreeViewTestData TestDataSource
        {
            get
            {
                if (_testDataSource == null)
                {
                    _testDataSource = new TreeViewTestData("rootItem", "this is the root and will be ignored", true);

                    TreeViewTestData item1 = new TreeViewTestData("Pie", "New flavours available", false);
                    item1.Add(new TreeViewTestData("Steak and ale", "Beef steak stewed in Westcountry Ale", false));
                    item1.Add(new TreeViewTestData("Chicken and mushroom", "A traditional favourite pie", false));


                    _testDataSource.Add(item1);
                    _testDataSource.Add(new TreeViewTestData("Cake", "Chocolate sponge", false));

                    TreeViewTestData item3 = new TreeViewTestData("Fruit", "A healthy option", true);
                    TreeViewTestData item3a = new TreeViewTestData("Apples", "Different varieties available", false);
                    TreeViewTestData item3b = new TreeViewTestData("Pears", "A juicy snack", true);
                    TreeViewTestData item3c = new TreeViewTestData("Oranges", "High in Vitamin C", false);

                    item3.Add(item3a);
                    item3.Add(item3b);
                    item3.Add(item3c);

                    TreeViewTestData item3a1 = new TreeViewTestData("Granny Smith", "A tangy green apple", false);
                    TreeViewTestData item3a2 = new TreeViewTestData("Goldern Delicious", "A crisp red apple", true);

                    item3a.Add(item3a1);
                    item3a.Add(item3a2);

                    _testDataSource.Add(item3);

                    TreeViewTestData item4 = new TreeViewTestData("Crisps", "Called 'chips' most places in the world, but 'crisps' in the UK", false);

                    item4.Add(new TreeViewTestData("Ready salted", "Perfect for a mid-morning snack", false));
                    item4.Add(new TreeViewTestData("Salt and Vinegar", "For those who like a little more tang", false));

                    _testDataSource.Add(item4);
                }
                return _testDataSource;
            }
        }

        /// <summary>
        /// This class represents the datasource and dataitems the HierarchicalRepeater control will bind to.
        /// It inherits HierarchyDataItemBase as required, and the additional properties are specific to this
        /// sample and can be data bound to in the ItemTemplate, ChildrenHeaderTemplate and FooterHeaderTemplate
        /// of the control.
        /// 
        /// The property "Expanded" has been added to represent the whether the tree node should be expanded or
        /// collapsed.
        /// </summary>
        private class TreeViewTestData : HierarchyDataItemBase
        {
            private string _description;

            public string Description
            {
                get { return _description; }
                set { _description = value; }
            }

            private string _text;

            public string Text
            {
                get { return _text; }
                set { _text = value; }
            }

            private bool _expanded;

            public bool Expanded
            {
                get { return _expanded; }
                set { _expanded = value; }
            }

            public TreeViewTestData(string text, string description, bool expanded)
            {
                _text = text;
                _description = description;
                _expanded = expanded;
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions