when binding the tree to a collection like
child 2.1.1 -> 2.3.1 won't be visible
some sample code
Create a new project, add the following code and run.
Uncomment the row : // root.Children[0].Children.Add(new NodeItem("hide me and child 2.1.1 -> child 2.3.1 will be invisible"))
---- code:
using System;using System.Collections.ObjectModel;using System.ComponentModel;using System.Windows.Forms;using Infragistics.Win.UltraWinTree; namespace BindTreeTest{ public class Form1 : Form { /// <summary> /// Required designer variable. /// </summary> private readonly IContainer components = null; private UltraTree ultraTree1; public Form1() { this.InitializeComponent(); var root = new NodeItem("root"); root.Children.Add(new NodeItem("child 1")); root.Children.Add(new NodeItem("child 2")); // if this node is hidden, the child 2.1.1 -> 2.1.3 nodes will not be visible // root.Children[0].Children.Add(new NodeItem("hide me and child 2.1.1 -> child 2.1.3 will be invisible")); root.Children[1].Children.Add(new NodeItem("child 2.1")); root.Children[1].Children.Add(new NodeItem("child 2.2")); root.Children[1].Children.Add(new NodeItem("child 2.3")); root.Children[1].Children[0].Children.Add(new NodeItem("child 2.1.1")); root.Children[1].Children[1].Children.Add(new NodeItem("child 2.2.1")); root.Children[1].Children[2].Children.Add(new NodeItem("child 2.3.1")); var collection = new ObservableCollection<NodeItem> {root}; this.ultraTree1.DataSource = collection; this.ultraTree1.ExpandAll(); } /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if (disposing && (this.components != null)) { this.components.Dispose(); } base.Dispose(disposing); } private void ultraTree1_ColumnSetGenerated(object sender, ColumnSetGeneratedEventArgs e) { e.ColumnSet.NodeTextColumn = e.ColumnSet.Columns["Text"]; } /// <summary> /// The main entry point for the application. /// </summary> [STAThread] private static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { var _override1 = new Infragistics.Win.UltraWinTree.Override(); this.ultraTree1 = new Infragistics.Win.UltraWinTree.UltraTree(); ((System.ComponentModel.ISupportInitialize) (this.ultraTree1)).BeginInit(); this.SuspendLayout(); // // ultraTree1 // this.ultraTree1.Dock = System.Windows.Forms.DockStyle.Fill; this.ultraTree1.Location = new System.Drawing.Point(0, 0); this.ultraTree1.Name = "ultraTree1"; _override1.ShowExpansionIndicator = Infragistics.Win.UltraWinTree.ShowExpansionIndicator.CheckOnDisplay; this.ultraTree1.Override = _override1; this.ultraTree1.Size = new System.Drawing.Size(579, 432); this.ultraTree1.TabIndex = 0; this.ultraTree1.ViewStyle = Infragistics.Win.UltraWinTree.ViewStyle.Standard; this.ultraTree1.ColumnSetGenerated += new Infragistics.Win.UltraWinTree.ColumnSetGeneratedEventHandler(this.ultraTree1_ColumnSetGenerated); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(579, 432); this.Controls.Add(this.ultraTree1); this.Name = "Form1"; this.Text = "Form1"; ((System.ComponentModel.ISupportInitialize) (this.ultraTree1)).EndInit(); this.ResumeLayout(false); } #endregion #region Nested type: NodeItem public class NodeItem : NodeItemBase { public NodeItem(string text) : base(text) { } } #endregion #region Nested type: NodeItemBase public abstract class NodeItemBase { protected NodeItemBase(string text) { this.Children = new ObservableCollection<NodeItemBase>(); this.Text = text; } public string Text { get; set; } public ObservableCollection<NodeItemBase> Children { get; private set; } } #endregion }}
Hi,
Hadn't heard back from you.
Please let me know if you have any follow up questions.
Our development staff has reviewed your development issue and they have concluded that it is not an issue with the WinTree. They have also relayed the following explanation:
The way the BindingManager in DotNet works is that it gets the structure of the child data from the first row of actual child data. So the tree asks the BindingManager for the structure of root node data and this works just fine, because there is a row at that level. Note that the node at this level has a column which describes the type of the child data, so getting the root node means we can display the root node and one level deeper.
It then walks down to the first child row, and it exists, so it gets the structure of that one, too. Once again, this level includes the structure of the level below it, so this also works fine.
Then it tries to walk down to the third level. At his point, it fails to get a child row, because there isn't one. The "child 1" node has no children. This is not a problem for the nodes immediately below child 1 or any of its siblings, but the BindingManager cannot return any data beyond that level.
The BindingManager is actually pretty clever; in a case like this it tries to create a new row, get its structure, and then remove the row with no one the wiser. But in this case it cannot do that because the DataType of the collection is an abstract class (NodeItemBase) and therefore the BindingManager cannot create an instance of it.
Ultimately, the problem in this case is that this DataSource is not suitable for binding.
Or Development staff also mentioned that the WinGrid actually handles this situation by checking for the ITypedList interface to get the structure and then working with the data on that particular level without using a BindingManager. They recommended that we might be able to do something like this in the tree, and suggested that I create a feature request for the WinTree
I have added a Feature Request, FR12720, in your name to modify the WinTree to be able to deal with Bound nodes when the BindingManager is unavailable to, like the WinGrid does.
They also provided a workaround for you. Remove the "abstract" qualifier on the "NodeItemBase" class and change the parameterless constructor on this class from protected to public. This would allow the BindingManager to create an instance of the NodeItemBase and thus retrieve its structure.
If you have any questions, please don't hesitate to let me know.
Mike asked me to log a development issue related to your questions.
I’m in the process of doing that and will contact you directly concerning the status of the development issue thru a case I have created for you.
You will hear from me shortly.
Marianne
Sorry about that, I must have missed that line of code.
The weird thing is that when I changed the code as I suggested above, and made the Children property with a lazy getter, it actually did change the behavior in a very noticeable way. I wonder why.
Anyway, since the grid is working okay here and the tree is not, I think there probably is some kind of bug in the tree, so I'm going to go ahead and have developer support write this up so we can look into it more thoroughly.
Dear Mike,
there is nothing wrong with the code. The children collection is never null since it will be initialized in the constructor:
public abstract class NodeItemBase { protected NodeItemBase(string text) { this.Children = new BindingList<NodeItemBase>(); this.Text = text; } public string Text { get; set; } public BindingList<NodeItemBase> Children { get; private set; } }
The objects are created before the tree is binded, so every object has been gone through the constructor.
if you setup the DataNodeInitialize event and you can do a debug.write on the childrencollection.count and you'll see
every child will be having a ChildrenCollection which has a size of >= 0