I have a WinTree which I want to totally populate via DataBinding. The root nodes are of one type and children nodes are of a totally different type. On the root node, the code calls:
treeNode.Nodes.SetDataBinding(childDataSource, string.empty);
And the children are displayed showing the first property of the object in which the given node is bound.
There should be two columns from the childDataSource displayed. How does one go about setting up a column set for the children such that dataBinding knows which columns in the dataset to bind to?
When I try putting in a property name, which happens to be a property of a derived class, there are no children:
class base { public string name { get; set; } }
class derived : base { string details { get; set; } }
class CustomDataSet : BindingList<derived> {}
I want to show both the name and details under the root. The root is of a different type not shows in this code
Sam
Hi Sam,
To set up a hierarchy, you should set up the hierarchy in your data source, rather than trying to bind the root nodes of the tree and then also bind the child nodes.
It looks like you are using a derived BindingList class. That's fine and will give you a single level of data. To get child data, the objects in the BindingList (in the example above, the derived object) must expose a public property that returns another BindingList which contains the child rows.
If you bind the tree to a BindingList whose items expose a BindingList property of their own, the tree will display the hierarchy for you automatically.
Normal 0 false false false MicrosoftInternetExplorer4
Ok, so the inheritance is not an issue, didn't think so.
I do agree 100% that setting up the binding in the data source is the quickest and easiest, but in my current situation this is not the case. It is my impression that since there is a method SetDataBinding() on treeNode.Nodes, that setting a data set on a node was something the control is able to do. Am I mistaken?
If I am not, what I am wondering is: How do I control which columns are displayed when using treeNode.Nodes. SetDataBinding()? Is this ONLY done via the data set?
Hi,
Yes, you are correct. You can bind an individual nodes collection, such as a collection of child nodes.
The ColumnSet for those nodes should be automatically generated, assuming you left the AutoGenerateColumnSets property to the default, which is true.
If the generated ColumnSet is wrong, there could be a number of reasons why.
The ColumnSets are matched up to the data source by name. So it's possible that if you are binding the root-level nodes of the tree that maybe there is a ColumnSet that already exists with the same name as the one you are binding the child nodes to.
Are you binding the root nodes of the tree?
What kind of data source are you using? If it's a DataSet or DataTable, then make sure you set the TableName on it to something unique.
Another option is that the ColumnSet somehow got generated at design-time with only one column because you bound the tree at design-time to the same data source before it had both columns in it. If that's the case, then you may have to reset the ColumnSets collection at design-time in order to get rid of the incorrect ColumnSet.
If none of the helps, I recommend that you trap the ColumnSetGenerated event and examine the ColumnSets that are getting created and that might provide some clue about what's going wrong.
If you want to manually create your ColumnSets, you could do that, also. You just have to either make sure the Key of the ColumnSet matches the name used by the band in the data source. Or else assign the ColumnSet explicitly via the Override.
In my application, DataTable are not getting to the UI level, so it is a BindingList of objects.
I believe I have things setup where there are multiple roots. I have a collection of this object:
public interface IQLibTreeItem : IComparable { string Name { get; } string Description { get; } void Populate(UltraTreeNode treeNode); }
Then the tree controls data source is set to a collection of these objects. Correct me of I am mistaken, but this makes this collection the root nodes, correct?
Two of the three different Populate() methods will populate children with the object in questions, the UDA3.Common.Data.QuestionItem.
I just created a ColumnSet and set the Key to QuestionItem. Added two column's, set them both to DataType of string, set the Key to the name of the properties I want to display from QuestionItem, and set the Text to the title of the column.
When I run the code I continue to get just the first property being displayed. When I hooked the ColumnSetGenerated event, it is only called once the first time I try to expand any one of the IQLibTreeItem nodes, the Key value is string.Empty.
scarleton said:DataTable are not getting to the UI level
I'm not sure what this means, but using a BindingList is fine.
scarleton said: I believe I have things setup where there are multiple roots. I have a collection of this object: public interface IQLibTreeItem : IComparable { string Name { get; } string Description { get; } void Populate(UltraTreeNode treeNode); } Then the tree controls data source is set to a collection of these objects. Correct me of I am mistaken, but this makes this collection the root nodes, correct?
No, this is not going to work. The DotNet BindingManager will not display interface members, it wil only display public properties on a class.
So if you have a BindingList of "IQLibTreeItem" objects, this will not work. If you have a BindingList of some class that implements this interface implicitly, then I think it will work. But if the items implement the interface explicity, it will not work.
scarleton said:Two of the three different Populate() methods will populate children with the object in questions, the UDA3.Common.Data.QuestionItem.
I'm not sure what this means. What are the "three different Populate() methods?"
I assume QuestionItem is a class that implements IQLibTreeItem.
scarleton said:I just created a ColumnSet and set the Key to QuestionItem. Added two column's, set them both to DataType of string, set the Key to the name of the properties I want to display from QuestionItem, and set the Text to the title of the column.
I don't think this will work. Since you are binding to a BindingList and not a table, it has no name. So setting the Key of the ColumnSet to "QuestionItem" will not match up with the actual name of the band provided by the BindingManager.
Try setting the key to an empty string.
Or... just assign the ColumnSet directly to the NodeLevelOverrides[0].ColumnSet
Or, just leave AutoGenerateColumnSets on the tree set to true and don't create any ColumnSets and the tree will generate one for you automatically and you don't have to do anything.
scarleton said:When I run the code I continue to get just the first property being displayed. When I hooked the ColumnSetGenerated event, it is only called once the first time I try to expand any one of the IQLibTreeItem nodes, the Key value is string.Empty.
This makes sense and it's what I was saying above. Since you are using a BindingList, your list has no name, and therefore the ColumnSet key is an empty string.
You say only the first property is displayed. Do you mean you are seeing a single Column? Or are you just getting standard-style nodes with no columns? If the former, then it sounds like your QuestionItem only has one public property. If the latter, then you must be setting the ViewStyle on the tree to Standard.
I'm not sure how you are intending to populate the child nodes here. The tree is not going to know anything about your Populate method or when to call it. So you will have to call it yourself. BNut if you already have a Populate method on the item, why not just expose the child list as a property instead of using a method? All you need is a property on the QuestionItem that returns another BindingList<T>. although, I guess if your QuestionItem is going to have child lists of varying types, you would have to bind the Nodes collection under each parent node to a completely different list.
scarleton said:If I understand everything correctly, ColumnSet’s simply will not do me any good because I am using objects and not DataTables. So it sounds like the ONLY solution is another wrapper class to contain QuestionItem class and expose only the properties I want displayed, is this correct?
No, that is not correct. ColumnSets are used in the tree whenever a node has columns. The type of data source is irrelevant. In fact, the existance of a data source is irrelevant - you can show columns for unbound nodes, as well.
If none of your BindingLists have names, then you probably need to create the ColumnSets yourself and assign them to the Nodes collection via the override. So in this example, when you call the Populate method, you would create a ColumnSet with two columns. Set the keys of the columns to the names of the field you want to display. Then set node.Nodes.Override.ColumnSet to the ColumnSet you created and only the two columns you create will be displayed.
scarleton said:If so, may I put in a feature request that, if the binding source is a class, the ColumnSet.Key look to the class name rather than a table name?
I don't believe this is possible. The tree gets the name of the band from the DotNet BindingManager. It doesn't look at the data source directly. So your request would really have to go to Microsoft to update the BindingManager behavior.
////////////////////////////////////////
// The base of all the top most nodes
public interface IQLibTreeItem : IComparable
{
string Name { get; }
string Description { get; }
void Populate(UltraTreeNode treeNode);
}
// 1 of 3 of the implementations of the top most node
public class AllCatItem : IQLibTreeItem
string Name { get { ...} }
string Description { get { ...}}
void Populate(UltraTreeNode treeNode) { ...}
// 2 of 3 of the implementations of the top most node
public class ATCatItem : IQLibTreeItem
// 3 of 3 of the implementations of the top most node
public class CategoryItem : IQLibTreeItem
//
When form is first initialized BindingList containing instances of the three classes above are bound to the tree control. In the UltraTree.BeforeExpand event, the IQLibTreeItem.Populate() is called, passing in the node that is to be expanded. At this point in time the children nodes are created. In all three implementations (AllCatItem, ATCatItem, CategoryItem) of the IQLibTreeItem.Populate() method, a database is queried to determine the children nodes. This Populate method gets a BindingList of objects and then calls UltraTreeNode.Nodes.SetDataBinding() on the node passed in to the method, which of course is the top node that is about to be expanded.
Some of the time the children nodes are an instance of the QuestionItem class. This class has a LOT of properties on it and I would only like to display two of those properties.
If I understand everything correctly, ColumnSet’s simply will not do me any good because I am using objects and not DataTables. So it sounds like the ONLY solution is another wrapper class to contain QuestionItem class and expose only the properties I want displayed, is this correct?
If so, may I put in a feature request that, if the binding source is a class, the ColumnSet.Key look to the class name rather than a table name?