BackgroundI am trying to display two tables in an UltraTree control: Location and Machine. The Location table is the hierarchy; the Machine table references the Location table.The tables have the following columns (the relevant ones):Location--------LocationPKNameParentLocationPKMachine-------MachineIDNameLocationPK(lots of other columns)Each node in the tree will have one of two types of children - any number of locations *or* exactly 1 machine.I want the tree to display the Location heirarchy using just the name column, and if they expand a name and it is referenced by a machine, show the machine details (quite a few columns of information).
ProblemCurrently whenever a Location node is expanded, it shows two child nodes - "Location" and "Machine". The user then has to expand the "Location" and "Machine" columns to see the next layer of details.Is there a way to hide the "Location" and "Machine" nodes from appearing, and instead show their children, when only one of those bands has children?
Edited to add: From the documentation on the UltraTreeColumnSettings.ShowBandNodes, it says: "Regardless of the setting of ShowBandNode, band nodes will always be created to separate siblling bands. In a case where a child band has no siblings, a band node will be created for it if ShowBandNodes is set to ShowBandNodes.Always"
Is there a way to hide a band from appearing when there are no child nodes for that band?
ExampleI am seeing this:- RootLocation - Location - ThisIsALocationName - AndAnother - Location - YetAnotherLocation - Location - Machine - AMachine | All | Columns | Appear | Here... - Machine - Machinebut want to see this instead:- RootLocation - ThisIsALocationName - AndAnother - YetAnotherLocation - AMachine | All | Columns | Appear | Here...Further DetailsI have created a DataSet and populated it with two tables, Location and Machine. I have added two relationships to the DataSet like so:
dataSet.Relations.Add("Location", rv.Tables["Location"].Columns["LocationPK"], rv.Tables["Location"].Columns["ParentLocationPK"], false);
dataSet.Relations.Add("Machine", rv.Tables["Location"].Columns["LocationPK"], rv.Tables["MachineColumns["LocationPK"], false);
I have looked through the examples in the WinTree folder in the Samples directory. I have not been able to find an example that uses two tables in one tree via a bound DataSet.
We have also considered styling the screen after the sample in folder "DataBinding (Navigation) CS"; however we'd like to see if this specific problem can be overcome as we will most likely encounter this situation again in the future.
Sorry for late answer:private void _tree_ColumnSetGenerated(object sender, ColumnSetGeneratedEventArgs e){ if (e.ColumnSet.Key == "Feature Details") { //default it has 2 children: childtable_1+ childtable_2 //but we only wanna show one of them, depends on the parent row is a child1 or child2 row //so create the 3 ColumnSet, one will contain only child1, other will contain only child2 //And later (_tree_AfterDataNodesCollectionPopulated()) we will set the appropriate ColumnSet to the node //1) make child1 ColumnSet: copy the original ,and remove the child2 node _columnSetFeatureDetailsChild1 = UltraTreeColumnSet.CloneSerializableObject(e.ColumnSet, null) as UltraTreeColumnSet; _columnSetFeatureDetailsChild1.Key = "_columnSetFeatureDetailsChild1"; int colPos = -1; bool colFound = false; foreach (UltraTreeNodeColumn col in _columnSetFeatureDetailsChild1.Columns) { ++colPos; if (col.Key == "Child2") break; } _columnSetFeatureDetailsChild1.Columns.RemoveAt(colPos); //2) make child2 ColumnSet: copy the original ,and remove the VS node _columnSetFeatureDetailsChild2 = UltraTreeColumnSet.CloneSerializableObject(e.ColumnSet, null) as UltraTreeColumnSet; _columnSetFeatureDetailsChild2.Key = "_columnSetFeatureDetailsChild2"; colPos = -1; colFound = false; foreach (UltraTreeNodeColumn col in _columnSetFeatureDetailsChild2.Columns) { ++colPos; if (col.Key == "Child1") break; } _columnSetFeatureDetailsChild2.Columns.RemoveAt(colPos);}private void _tree_AfterDataNodesCollectionPopulated(object sender, AfterDataNodesCollectionPopulatedEventArgs e){ foreach (UltraTreeNode node in e.Nodes) { if (node.DisplayColumnSetResolved.Key == "Feature Details") { bool rowChild1 = false; bool rowChild2 = false; foreach (UltraTreeNodeCell cell in node.Cells) { if (cell.Key.ToLower() == "property") if (cell.Text.ToLower() == "child1") rowChild1 = true; else if (cell.Text.ToLower() == "child2") rowChild2 = true; } if (rowChild1) node.Override.ColumnSet = _columnSetFeatureDetailsChild1; else if (rowChild2) node.Override.ColumnSet = _columnSetFeatureDetailsChild2; }}
Hi,
I'm implementing an identical scenario and am having problems getting the tree to display correctly (similar to your 'after' screenshot). Could you possibly provide a sample code of how you implemented the ColumnSetGenerated event (including how you used the UltraTreeColumnSet.CloneSerializableObject(..)) and the InitializeDataNode() and any other member events that I should be aware of.
Really appreciate a quick a response.
Thanks,Assad
Thank you very much Mike, it works!
1) In ColumnSetGenerated() you can create your own ColumSet: create a copy (with UltraTreeColumnSet.CloneSerializableObject(..)) and remove the not necessary columns.
2) In AfterDataNodesCollectionPopulated() you can analyze the Node.Cells data, and if necessary, you can set the node.Override.ColumnSet to your own (these were created in step 1))InitializeDataNode() was not good for me, as there you don't have celldata yet
Attaching a screenshot about the result. Very nice! Thanks.
pxclient said:What is the best place to make this ColumnSet copy? In ColumnSetGenerated()?
That seems like a good place to do it. In a simple case where you have two child bands and you want to show one of the other, you really only need to make one copy and then just hide one of the child bands in the auto-generated column set. This way, the child band will always be hidden unless you apply the copied columnset to a node.
pxclient said:And how to make a copy of a ColumnSet? Is there any simple one-call way?
I'm not sure off the top of my head. See if there's a Clone method. If not, then what you could do is, instead of making a copy, you could auto-generate a second ColumnSet from the same data and modify it to remove the child band. There's a static method that allows you to pass in a DataSource and DataMember and auto-generates a column set for you.
UltraTreeColumnSet.FromDataSource(dataSource, dataMember)
pxclient said:How can I change the ColumnSet of a Node? Silly, but I cannot find, it has a DataColumnSetResolved, but it's read-only.
It's on the Override:
node.Override.ColumnSet
pxclient said:And where / when is the best place to change it to my local DataSouce copy?
I'd use the InitializeDataNode event to start with and see if that works.
Hi Mike,thanks the idea! Could you please help me a little bit how/where to do these?Let's see.My ColumnSet is generated automatically when I set tree.DataSource/DataMember. (it's quite a complex data model, with lot's of tables, relations)What I have to do, when that node is expanded, then it's ColumnSet is generated on-demand, I have to make 2 copy of it, removing the not necessary columns (Band), and based on the parent data, have to assign the correct one to the Node.What is the best place to make this ColumnSet copy? In ColumnSetGenerated()?And how to make a copy of a ColumnSet? Is there any simple one-call way?How can I change the ColumnSet of a Node? Silly, but I cannot find, it has a DataColumnSetResolved, but it's read-only.And where / when is the best place to change it to my local DataSouce copy?Thank you very much