Hello,
Mainly I can't understand why I don't see node (Level 3) in case "wrong" in test example?
Cases wrong and right differ only of their order of nodes.
And one more question.
If i remove line 49
(ultraTreeNodeColumn1.DataType = typeof(string);)
in file Form1.Designer.cs
the tree looks like list
How it related with type of column?
I am using Infragistics2.Win.UltraWinTree.v10.3.dll (version 10.3.20103.1000)
Thank you
Roman
I tested version 12.2 and it shows the same
Hi Roman,
The DotNet BindingManager determines the data structure using the first node. So in this case, when you click "Wrong", your first node has a single child node whicih has no children. Therefore the depth of the entire data structure is established at that point and the second and subsequent nodes will never show anything past the first child level.
You need to set this up in such a way that the Children always returns an empty collection, rather than returning null. Also, if the Children collection is empty, the BindingManager will not be able to determine the structure of the data on that level. The usual way it handles this is that it tries to add an item to the list and then cancel it. But in your case, that won't be possible since your data source doesn't implement ICancelAddNew or IEditableObject.
Also, the code as you have it here is very difficult to read and understand. I've never seen anyone use a BindingList of BindingLists with a Children property that returns itself. This is a very unusual scenario and I wouldn't be surprised if it caused a lot of unpredictable behaviors.
Hi Mike
1. I don't sure if I understand of you about null value. You can see in my test, Children never can be null.
I think first node should not determine the depth for full tree. It is some abstract hierarchy structure.
Else, the tree can be used just in some limited cases that I should keep in mind.
2. In case I use List<> instead of BindingList<>, behaviour is same.
But I don't understand why you worried about of type. It should work for any implementation IEnumerable<>. It is base abstract case.
3. If you don't like that Node inherits something, look another one:
public partial class Form1 : Form { public Form1() { InitializeComponent(); ultraTree1.ShowRootLines = true; RadioButtonCheckedChanged(radioButton1, EventArgs.Empty); } private readonly Node node0 = new Node("Node (no children)"); private readonly Node node1 = new Node("Node (level 1)", new Node("Node (level 2)", new Node("Node (level 3)"))); private void RadioButtonCheckedChanged(object sender, EventArgs e) { ultraTree1.DataMember = "Children"; ultraTree1.DataSource = radioButton1.Checked ? new Node("root", node0, node1) : new Node("root", node1, node0); ultraTree1.ExpandAll(ExpandAllType.Always); } } public class Node { public Node(string text, params Node[] children) { Text = text; this.children = children.ToList(); } public string Text { get; private set; } private readonly List<Node> children; public List<Node> Children { get { return children; } } }
public partial class Form1 : Form
{ public Form1() { InitializeComponent(); ultraTree1.ShowRootLines = true; RadioButtonCheckedChanged(radioButton1, EventArgs.Empty); }
private readonly Node node0 = new Node("Node (no children)");
private readonly Node node1 = new Node("Node (level 1)", new Node("Node (level 2)", new Node("Node (level 3)")));
private void RadioButtonCheckedChanged(object sender, EventArgs e) { ultraTree1.DataMember = "Children"; ultraTree1.DataSource = radioButton1.Checked ? new Node("root", node0, node1) : new Node("root", node1, node0); ultraTree1.ExpandAll(ExpandAllType.Always); } }
public class Node { public Node(string text, params Node[] children) { Text = text; this.children = children.ToList(); }
public string Text { get; private set; }
private readonly List<Node> children;
public List<Node> Children { get { return children; } } }
Notice that Node inherits nothing, it doesn't use BindingList and Children don't return null.
4. I tried Node to implement ICancelAddNew, but it is not used.
5. Unfortunatelly I can't see any manuals how I can use UltraTree with my business objects. I saw just examples with DataSets or with adding node items one to another.
6. You said nothing about the second question (about datatype) in original post.
I hope for help
The code you have here won't compile because you are setting your List<Node> to an array. But anyway, I fixed that and changed Children to a BindingList<Node> (which is a much better data source for binding) and I still get the same results.
My original explanation was incomplete. Here's what's happening:
1) You bind the tree to the Children of the Root node.
2) There are two child nodes in this list (Node0, and Node1). Since the list is not null and has items in it, the BindingManager is able to get the data structure, no problem.
3) The tree can see that this data structure includes a Children property which is of type BindingList<Node>. Since it knows the items in the list are Nodes, it has no problem getting the data structure for level 2 (the children of Node0/Node1).
4) But that's the end of the chain. Once you get to that point, the root-level node has no more nodes in the hierarchy. So the binding manager can't get a node at level 2, it cannot know what the structure of the level 3 nodes is - or that there even exists a level 3.
Just to be clear once again - this has nothing to do with the WinTree control. It's a limitation of the BindingManager in DotNet.
In order for this to work, you would have to set up your data source in such a way that the BindingManager could add a node under Node0 and then cancel it. This is tricky. In order to add a node, you Node object needs a parameterless constructor.Your current Node object requires parameters so the BindingManager cannot add one to the collection.
I fixed that, but I'm still not able to get this to work. For some reason, when the BindingManager tries to add a node to the third level, it's blowing up with an exception that the collection is read-only. I will have to look into this a little more and see if I can figure out what's going on. I know there have been many posts about the same issue in the past.
Regarding the DataType, I'm afraid I don't understand what you are asking. Why would you set the DataType on the column? The tree is creating the ColumnSets automatically with the correct types.
Hello Roman,
Setting the datasource to null prior should not impact the sample or required for that matter. Please make sure you are using the latest service release if you cannot upgrade to our latest ( 14.2. )
Installing the latest service release for Infragistics helps keep your application up to date for the version used. For information on how to get the latest service release, see "How to get the latest service release" http://ko.infragistics.com/community/forums/t/29398.aspx
For general information about service packs, see our Service Release Schedule http://ko.infragistics.com/support/service-releases
Let me know if you have any questions regarding this matter.
Thank you Mike!
It seems it works now. So I missed only creating of children collection in default constructor.
One more thing I should add. It is to set null in ultraTree1.DataSource before set data.
this.ultraTree1.DataSource = null;this.ultraTree1.DataSource = nodes;
Else, your example doesn't work for me again.May be it is because of different versions.
Mike Saltzman said:I was passing the array of nodes into the constrcutor of the new BindingList of Children
Mike, BindingList doesn't have constructor that eats any array.
Best regards
Okay, I got it working. I am attaching a small sample project here that works correctly.
There were several key factors, some of which I already mentioned.
First, your Node object has to have a parameterless constructor so that the BindingManager can add (and Cancel) an item when there are no items on the list.
As I mentioned, after that, I was getting an error that the collection is read-only. This was caused by the code that was populating the child collection in your constructor. I was passing the array of nodes into the constrcutor of the new BindingList of Children, but since the array cannot be added to, that means the collection cannot be added to. So this was simply a matter of creating the children BindingList and then looping through the array to add the items.
Hi Mike,
I didn't set list to array, but it doesn't matter.
I tried some things and found one case when my case works fine.
(I should use BindingList and I should support default constructor Node())
But I caught some error later.
It is not important for my task because I use static datasource.
But please check if it is bug of infragistics or not.
using System;using System.ComponentModel;using System.Linq;using System.Windows.Forms;using Infragistics.Win.UltraWinTree; namespace UltraTreeDepthTest{ public partial class Form1 : Form { public Form1() { InitializeComponent();RadioButtonCheckedChanged(radioButton1, EventArgs.Empty); RadioButtonCheckedChanged(radioButton1, EventArgs.Empty); RadioButtonCheckedChanged(radioButton1, EventArgs.Empty); } private readonly Node node0 = new Node("Node (no children)"); private readonly Node node1 = new Node("Node (level 1)", new Node("Node (level 2)", new Node("Node (level 3)"))); private void RadioButtonCheckedChanged(object sender, EventArgs e) { ultraTree1.DataMember = "Children"; ultraTree1.DataSource = radioButton1.Checked ? new Node("root", node0, node1) : new Node("root", node1, node0); ultraTree1.ExpandAll(ExpandAllType.Always); } } public class Node { public Node() { } public Node(string text, params Node[] children) { Text = text; this.children = new BindingList<Node>(children.ToList()); } public string Text { get; private set; } private readonly BindingList<Node> children; public BindingList<Node> Children { get { return children; } } }}
using System;using System.ComponentModel;using System.Linq;using System.Windows.Forms;using Infragistics.Win.UltraWinTree;
namespace UltraTreeDepthTest{ public partial class Form1 : Form { public Form1() { InitializeComponent();RadioButtonCheckedChanged(radioButton1, EventArgs.Empty); RadioButtonCheckedChanged(radioButton1, EventArgs.Empty); RadioButtonCheckedChanged(radioButton1, EventArgs.Empty); }
public class Node { public Node() { }
public Node(string text, params Node[] children) { Text = text; this.children = new BindingList<Node>(children.ToList()); }
private readonly BindingList<Node> children;
public BindingList<Node> Children { get { return children; } } }}
notice that I set datasource 3 times!
In this case empty node appears.
Empty child is appeared:
If yo will delete duplicated RadioButtonCheckedChanged(radioButton1, EventArgs.Empty);
everything will be ok for the first time, but you can see this behaviour if you will to change wrong and right several times.
I think it is related problem. I very hope you will find and fix it and it will fix original issue.
About datatypes.
I don't want to use automatically ColumnSets. It can show me columns that I don't need.
I commented just 1 line in example and you can see it on screenshot: