Child nodes loaded on demand

14 posts, 1 answers
  1. Sonya L
    Sonya L avatar
    36 posts
    Member since:
    Dec 2009

    Posted 10 Nov 2010 Link to this post

    I have a situation where I want to create a treeview that has 4 levels.  I want to immediately load the first two levels, and only load levels 3 and 4 for a particular level 2 node when it is expanded.  I would like all of these nodes to be bound to a datatable(s) for ease of updating the data.  What would be the best way to accomplish this?  I am experimenting with both related tables in a hierarchy, and a self-referencing table, but haven't seen the exact results I am looking for.  Thanks for your help!
  2. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 10 Nov 2010 Link to this post

    Hello Sonya, 

    You can use the LoadOnDemand feature of the RadTreeView for all child nodes, and get the child nodes that you need from the database as the NodeExpandedChanged event is firing. 

    For more information, please refer to this documentation link

    Hope that helps
    Richard
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Sonya L
    Sonya L avatar
    36 posts
    Member since:
    Dec 2009

    Posted 10 Nov 2010 Link to this post

    Is there a way to have the child nodes (levels 3 and 4) bound to a datatable, rather than creating them manually, as in the example?
  5. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 10 Nov 2010 Link to this post

    Hello Sonya, 

    As far as I'm aware, you cannot mix bound and unbound modes in this control. You would need to create them all manually, though you could get the levels 3 and 4 from the database and iterate over a reader or object collection that had been brought in from the database. 

    hope this helps
    Richard
  6. Emanuel Varga
    Emanuel Varga avatar
    1336 posts
    Member since:
    May 2010

    Posted 10 Nov 2010 Link to this post

    Hello Sonya,

    I would suggest something different, to use some middle tier logic, more precisely a binding list, and load all the data from the db in that binding list, please take a look at the following example:
    using System;
    using System.ComponentModel;
    using System.Windows.Forms;
    using Telerik.WinControls.UI;
     
    namespace TreeViewLazyLoad
    {
        public partial class Form1 : Form
        {
            private RadTreeView radTreeView1;
            private NodesList nodes;
            public Form1()
            {
                InitializeComponent();
                this.Controls.Add(radTreeView1 = new RadTreeView());
                radTreeView1.Dock = DockStyle.Fill;
            }
     
            protected override void OnLoad(EventArgs e)
            {
                base.OnLoad(e);
                radTreeView1.LoadOnDemand = true;
                radTreeView1.NodeExpandedChanged += new RadTreeView.TreeViewEventHandler(radTreeView1_NodeExpandedChanged);
                nodes = new NodesList();
                nodes.GetFirstLevel();
                nodes.GetSecondLevel();
                radTreeView1.DataSource = nodes;
                radTreeView1.ParentIDMember = "ParentId";
                radTreeView1.ValueMember = "Id";
                radTreeView1.DisplayMember = "Name";
            }
     
            void radTreeView1_NodeExpandedChanged(object sender, RadTreeViewEventArgs e)
            {
                if (e.Node.Nodes.Count == 0)
                {
                    var node = e.Node.DataBoundItem as Node;
                    nodes.GetChildNodesForNode(node.Id);
                }
            }
        }
     
        public class Node
        {
            public int Id
            {
                get;
                set;
            }
     
            public int ParentId
            {
                get;
                set;
            }
     
            public string Name
            {
                get;
                set;
            }
        }
     
        public class NodesList : BindingList<Node>
        {
            public NodesList()
            {
            }
     
            public void GetFirstLevel()
            {
                for (int i = 0; i < 4; i++)
                {
                    this.Add(new Node
                    {
                        Id = i,
                        Name = "Name" + i,
                        ParentId = i
                    });
                }
            }
     
            public void GetSecondLevel()
            {
                for (int i = 4; i < 8; i++)
                {
                    this.Add(new Node
                    {
                        Id = i,
                        Name = "Name" + i,
                        ParentId = i - 4
                    });
                }
            }
     
            public void GetChildNodesForNode(int id)
            {
                var startIndex = this.Count;
                for (int i = startIndex; i < startIndex + 4; i++)
                {
                    this.Add(new Node
                    {
                        Id = i,
                        Name = "Name" + i,
                        ParentId = id
                    });
                }
            }
        }
    }

    Basically here, I'm loading the first 2 levels, and after that on node expand just get the data from the db and add it to the list.

    Hope this helps, if you have any other questions or comments, please let me know,

    Best Regards,
    Emanuel Varga
  7. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 10 Nov 2010 Link to this post

    Hi All,

    I agree. I hadn't thought of that and beleive that this solution should work well for your scenario

    All the best
    Richard
  8. Sonya L
    Sonya L avatar
    36 posts
    Member since:
    Dec 2009

    Posted 10 Nov 2010 Link to this post

    I'll try that, thanks!
  9. Emanuel Varga
    Emanuel Varga avatar
    1336 posts
    Member since:
    May 2010

    Posted 10 Nov 2010 Link to this post

    Glad to be able to help,

    If you have any more questions please just let me know, and if the question has been solved, please mark the question as answered, so that others can find the answers to their questions faster.

    Best Regards,
    Emanuel Varga
  10. Sonya L
    Sonya L avatar
    36 posts
    Member since:
    Dec 2009

    Posted 11 Nov 2010 Link to this post

    This example seems to work well, thanks!  Now I am trying to clear out the Binding List, and reload it based on a user action, but the tree does not display anything.  When the app first loads, I load the Binding List as in the example, and it works fine.  When I want to change the contents of the list, I set the tree's datasource to Nothing, clear the list, reload the binding list, and rebind it to the tree.  When I do this, the tree is blank.  What could I be missing?  Thanks!
  11. Emanuel Varga
    Emanuel Varga avatar
    1336 posts
    Member since:
    May 2010

    Posted 11 Nov 2010 Link to this post

    Hello Sonya,

    Why are you clearing the list? Why are you setting the datasource to nothing(null)?
    Because it is a bindinglist, it will notify the tree on changes so you don't have to remove the datasource, just change the data inside the bindinglist.

    Hope this helps, if you have any other questions or comments, please let me know,

    Best Regards,
    Emanuel Varga
    Telerik WinForms MVP
  12. Sonya L
    Sonya L avatar
    36 posts
    Member since:
    Dec 2009

    Posted 11 Nov 2010 Link to this post

    I want to show a different tree, that is why I am clearing the list.  Basically, the user can pick different 'views' of the data, so the tree has to change entirely.
  13. Answer
    Emanuel Varga
    Emanuel Varga avatar
    1336 posts
    Member since:
    May 2010

    Posted 11 Nov 2010 Link to this post

    Hello again,

    Based on what you were saying I've updated the example, please tell me if something should be different:
    using System;
    using System.ComponentModel;
    using System.Windows.Forms;
    using Telerik.WinControls.UI;
     
    public partial class Form1 : Form
    {
        private RadTreeView radTreeView1;
        private NodesList nodes;
        private int view;
     
        public Form1()
        {
            InitializeComponent();
            this.Controls.Add(radTreeView1 = new RadTreeView());
            radTreeView1.Dock = DockStyle.Fill;
     
            var view1Button = new RadButton();
            view1Button.Text = "View1";
            view1Button.Click += new EventHandler(view1Button_Click);
            view1Button.Dock = DockStyle.Bottom;
            this.Controls.Add(view1Button);
     
            var view2Button = new RadButton();
            view2Button.Text = "View2";
            view2Button.Click += new EventHandler(view2Button_Click);
            view2Button.Dock = DockStyle.Bottom;
            this.Controls.Add(view2Button);
        }
     
        void view1Button_Click(object sender, EventArgs e)
        {
            ReloadData(1);
        }
     
        void view2Button_Click(object sender, EventArgs e)
        {
            ReloadData(2);
        }
     
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            radTreeView1.LoadOnDemand = true;
            radTreeView1.NodeExpandedChanged += new RadTreeView.TreeViewEventHandler(radTreeView1_NodeExpandedChanged);
            nodes = new NodesList();
            ReloadData(1);
            radTreeView1.DataSource = nodes;
            radTreeView1.ParentIDMember = "ParentId";
            radTreeView1.ValueMember = "Id";
            radTreeView1.DisplayMember = "Name";
        }
     
        private void ReloadData(int view)
        {
            radTreeView1.DataSource = null;
            nodes.Clear();
            this.view = view;
            nodes.GetFirstLevel(view);
            nodes.GetSecondLevel(view);
            radTreeView1.DataSource = nodes;
        }
     
        void radTreeView1_NodeExpandedChanged(object sender, RadTreeViewEventArgs e)
        {
            if (e.Node.Nodes.Count == 0)
            {
                var node = e.Node.DataBoundItem as Node;
                nodes.GetChildNodesForNode(node.Id, view);
            }
        }
    }
     
    public class Node
    {
        public int Id
        {
            get;
            set;
        }
     
        public int ParentId
        {
            get;
            set;
        }
     
        public string Name
        {
            get;
            set;
        }
    }
     
    public class NodesList : BindingList<Node>
    {
        public NodesList()
        {
        }
     
        public void GetFirstLevel(int view)
        {
            for (int i = 0; i < 4; i++)
            {
                this.Add(new Node
                {
                    Id = i + view,
                    Name = "Name" + i + view,
                    ParentId = i + view
                });
            }
        }
     
        public void GetSecondLevel(int view)
        {
            for (int i = 4; i < 8; i++)
            {
                this.Add(new Node
                {
                    Id = i + view,
                    Name = "Name" + i + view,
                    ParentId = i + view - 4
                });
            }
        }
     
        public void GetChildNodesForNode(int id, int view)
        {
            var startIndex = this.Count;
            for (int i = startIndex; i < startIndex + 4; i++)
            {
                this.Add(new Node
                {
                    Id = (i + view),
                    Name = "Name" + i + view,
                    ParentId = id
                });
            }
        }
    }

    Hope this helps, if you have any other questions or comments, please let me know,

    Best Regards,
    Emanuel Varga

    Telerik WinForms MVP
  14. Stefan
    Admin
    Stefan avatar
    2890 posts

    Posted 16 Nov 2010 Link to this post

    Hello,

    Thank you all for writing.

    Sonya, I hope that you find the solution provided by Emanuel helpful. Please let us know if you need further assistance.

    Emanuel, thank you for your help.

    Sincerely yours,
    Stefan
    the Telerik team
    See What's New in RadControls for WinForms in Q3 2010 on Wednesday, November 17, 11am Eastern Time: Register here>>
  15. Sonya L
    Sonya L avatar
    36 posts
    Member since:
    Dec 2009

    Posted 17 Nov 2010 Link to this post

    Emanuel

    Thanks for your help.  I was able to get it working with the following modifications.  For some reason, setting the datasource to null just caused a blank treeview.  Also, without the Begin/End Update, the app would hang when I tried to change views.  It seems to work now though.  Thanks!

    private void ReloadData(int view)
        {
    //added this
    radTreeView1.BeginUpdate();

    //replaced this
            //radTreeView1.DataSource = null;
    radTreeView1.Nodes.Clear();

            nodes.Clear();
            this.view = view;
            nodes.GetFirstLevel(view);
            nodes.GetSecondLevel(view);

    //removed this
            //radTreeView1.DataSource = nodes;

    //added this
    radTreeView1.EndUpdate();
        }
    private void ReloadData(int view)
        {
        //added this
        radTreeView1.BeginUpdate();
     
        //replaced this
            //radTreeView1.DataSource = null;
        radTreeView1.Nodes.Clear();
     
            nodes.Clear();
            this.view = view;
            nodes.GetFirstLevel(view);
            nodes.GetSecondLevel(view);
     
        //removed this
            //radTreeView1.DataSource = nodes;
     
        //added this
        radTreeView1.EndUpdate();
        }


    private void ReloadData(int view)
        {
    //added this
    radTreeView1.BeginUpdate();

    //replaced this
            //radTreeView1.DataSource = null;
    radTreeView1.Nodes.Clear();

            nodes.Clear();
            this.view = view;
            nodes.GetFirstLevel(view);
            nodes.GetSecondLevel(view);

    //removed this
            //radTreeView1.DataSource = nodes;

    //added this
    radTreeView1.EndUpdate();
      
Back to Top
UI for WinForms is Visual Studio 2017 Ready