This is a migrated thread and some comments may be shown as answers.

How to Display Object-related Data with recursive objects...

2 Answers 217 Views
Treeview
This is a migrated thread and some comments may be shown as answers.
Joe
Top achievements
Rank 1
Joe asked on 18 Mar 2012, 04:04 AM
I have a TreeView that I would like to display a set of objects where they each contain a list<> or BindingList<> of objects of the same type as the base class. It is a recursive type. I am having a hell of a time getting this list to display anything other than the root list. The more I tinker with the ChildMember or DisplayMember I get either nothing displayed or I get an error:

System.InvalidOperationException was unhandled
  Message=Failed to compare two elements in the array.
  Source=mscorlib
  StackTrace:
       at System.Collections.Generic.ArraySortHelper`1.BinarySearch(T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
       at System.Array.BinarySearch[T](T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
       at System.Collections.Generic.List`1.BinarySearch(Int32 index, Int32 count, T item, IComparer`1 comparer)
       at Telerik.WinControls.UI.BindingProvider.TreeNodeList.GetOrAdd(Object key)
       at Telerik.WinControls.UI.BindingProvider.BuildIndex(Int32 index)
       at Telerik.WinControls.UI.BindingProvider.GetNodes(RadTreeNode parent)
       at Telerik.WinControls.UI.RadTreeNode.get_Nodes()
       at Telerik.WinControls.UI.BindingProvider.Reset()
       at Telerik.WinControls.UI.BindingProvider.root_PropertyChanged(Object sender, PropertyChangedEventArgs e)
       at Telerik.WinControls.UI.RelationBinding.OnPropertyChanged(String propertyName)
       at Telerik.WinControls.UI.RelationBinding.set_DataSource(Object value)
       at Telerik.WinControls.UI.BindingProvider.set_DataSource(Object value)
       at Telerik.WinControls.UI.RadTreeView.set_DataSource(Object value)
       at WorkBreakdownStructure.Forms.frmWorkBreakdownStructureEditor..ctor() in C:\[Development]\CSLA_Research_Program\WorkBreakdownStructure\Forms\frmWorkBreakdownStructureEditor.cs:line 33
       at CSLA_Research_Program.Form1.button2_Click(Object sender, EventArgs e) in C:\[Development]\CSLA_Research_Program\CSLA_Research_Program\Form1.cs:line 29
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at CSLA_Research_Program.Program.Main() in C:\[Development]\CSLA_Research_Program\CSLA_Research_Program\Program.cs:line 18
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.ArgumentException
       Message=Argument_ImplementIComparable
       Source=Telerik.WinControls.UI
       StackTrace:
            at Telerik.WinControls.UI.BindingProvider.TreeNodeList.NodeComparer.Compare(Node x, Node y)
            at System.Collections.Generic.ArraySortHelper`1.InternalBinarySearch(T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
            at System.Collections.Generic.ArraySortHelper`1.BinarySearch(T[] array, Int32 index, Int32 length, T value, IComparer`1 comparer)
       InnerException:


This is my code...
Thanks



        public frmWorkBreakdownStructureEditor()
        {
            InitializeComponent();

            this.radTreeView1.ChildMember = @"Things";
            this.radTreeView1.DisplayMember = @"Name";
            this.radTreeView1.DataSource = GetDefaultThings();
        }


        private Things GetDefaultThings()
        {
            Thing t = new Thing("Object 1");
            Thing tc = new Thing("o2");
            t.Things.Add(tc);
            t.Things.Add(new Thing("o3"));
            t.Things.Add(new Thing("o4"));
            t.Things.Add(new Thing("o5"));
            t.Things.Add(new Thing("o6"));
            t.Things.Add(new Thing("o7"));
            tc.Things.Add(new Thing("gc1"));
            tc.Things.Add(new Thing("gc2"));
            tc.Things.Add(new Thing("gc3"));
            tc.Things.Add(new Thing("gc4"));
            Things ts = new Things();
            ts.Add(t);
            ts.Add(new Thing("Object2"));
            ts.Add(new Thing("Object3"));
            ts.Add(new Thing("Object4"));
            ts.Add(new Thing("Object5"));
            return ts;
        }
    }

    public class Things : BindingList<Thing>    {    }

    public class Thing
    {
        public Thing() { }
        public Thing(String name) : this() { _name = name; }

        private String _name = "";
        public String Name
        {
            get { return _name; }
            set { _name = value; }
        }

        private Things _things = new Things();
        public Things Things { get { return _things; } }
    }

2 Answers, 1 is accepted

Sort by
0
Joe
Top achievements
Rank 1
answered on 18 Mar 2012, 04:44 AM
It appears I was using the wrong separator "/" where "\" is the correct one instead.
Now I'm curious how this property works on the TreeView. It seems ChildMember is a list of property names that will be found at each level deep. There is no exception apparently to the property name at a specific depth.

The reason I ask is if you use recursion, then you have to specify the ChildMember as


            String childMember = @"Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            childMember += @"\Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            childMember += @"\Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            childMember += @"\Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            childMember += @"\Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            childMember += @"\Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            childMember += @"\Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            childMember += @"\Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            childMember += @"\Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            childMember += @"\Things\Things\Things\Things\Things\Things\Things\Things\Things\Things";
            this.radTreeView1.ChildMember = childMember ;

It appears the limit to how far this control will display child elements depends on how many element names you explicitly code for so if you want 100 deep then type the name 100 times...

How will this work if you have various object types with a child collection that has a different name from that of another object at the same level... It would appear the display of the collection for some times would be broken.

Also how about the limit on depth or how many elements deep? is there a limit? or is it possible to specify a recursive child element???

Thanks!
0
Julian Benkov
Telerik team
answered on 21 Mar 2012, 02:23 PM
Hello Joe,

The most suitable approach for your scenario is to use the load-on-demand feature of RadTreeView to load Nodes. Here is a sample application:

using System.Collections.Generic;
using System.Windows.Forms;
using Telerik.WinControls.UI;
 
namespace Lab.Tree
{
    public partial class TreeRecursiveObjectRelation : MainForm
    {
        private RadTreeView treeView = new RadTreeView();
        private List<Item> items = new List<Item>();
 
        public TreeRecursiveObjectRelation()
        {
            InitializeComponent();
 
            treeView.NodesNeeded += new NodesNeededEventHandler(treeView_NodesNeeded);
            treeView.Dock = DockStyle.Fill;
            treeView.Parent = this;
            treeView.BringToFront();
 
            items.Add(new Item("Level0_1"));
            items.Add(new Item("Level0_2"));
            items.Add(new Item("Level0_3"));
            items[0].Items.Add(new Item("Level1_1"));
            items[0].Items.Add(new Item("Level1_2"));
            items[1].Items.Add(new Item("Level1_3"));
            items[1].Items[0].Items.Add(new Item("Level1_3"));
        }
 
        void treeView_NodesNeeded(object sender, NodesNeededEventArgs e)
        {
            if (e.Parent == null)
            {
                for (int i = 0; i < this.items.Count; i++)
                {
                    ItemTreeNode node = new ItemTreeNode(this.items[i]);
                    e.Nodes.Add(node);
                }
 
                return;
            }
 
            ItemTreeNode parent = e.Parent as ItemTreeNode;
            for (int i = 0; i < parent.Item.Items.Count; i++)
            {
                ItemTreeNode node = new ItemTreeNode(parent.Item.Items[i]);
                e.Nodes.Add(node);
            }
        }
 
        class ItemTreeNode : RadTreeNode
        {
            private Item item;
 
            public ItemTreeNode(Item item)
            {
                this.item = item;
                this.Text = item.Name;
            }
 
            public Item Item
            {
                get
                {
                    return item;
                }
            }
        }
 
        class Item
        {
            private List<Item> items = new List<Item>();
 
            public Item()
            {
 
            }
 
            public Item(string name)
            {
                this.Name = name;
            }
 
            public List<Item> Items
            {
                get
                {
                    return this.items;
                }
            }
 
            public string Name { get; set; }
        }
    }
}

I hope this helps. Let me know if you need further assistance.
All the best,
Julian Benkov
the Telerik team
RadControls for WinForms Q1'12 release is now live! Check out what's new or download a free trial >>
Tags
Treeview
Asked by
Joe
Top achievements
Rank 1
Answers by
Joe
Top achievements
Rank 1
Julian Benkov
Telerik team
Share this question
or