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

3 posts, 0 answers
  1. Joe
    Joe avatar
    2 posts
    Member since:
    Mar 2012

    Posted 17 Mar 2012 Link to this post

    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. Joe
    Joe avatar
    2 posts
    Member since:
    Mar 2012

    Posted 17 Mar 2012 Link to this post

    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!
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Julian Benkov
    Admin
    Julian Benkov avatar
    1135 posts

    Posted 21 Mar 2012 Link to this post

    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 >>
Back to Top