Make a TreeView alter the BindingSource.Position

cjard

Well-known member
Joined
Apr 25, 2006
Messages
7,081
Programming Experience
10+
I have a datatable with some hierarchical data in it, and it is represented in a treeview in hierarchy form. Its a basic 1 level deep tree. In each leaf node's tag I store a reference to the row in the table, because when a leaf is selected, I use this row to set the .Filter of the bindingsource so that the main area of the screen shows details only for that line of data.

What I'd really like to do, is bind the tree up in some way so that navigating the tree alters the .Position of the bindingsource instead, like when you select Row X of a datagrid, it updates the position - how can I know the position?

Should I iterate the bindingSource List instead of the datatable when filling the tree?
 
Maybe use TAG, AfterSelect, and a BindingSource

Is BindingSource.Find ok to use in your app? It would return an integer to set the BindingSource.Position with.

Don't know if what would affect in your app but could use the tag to store the PK field(if single field). Then of treeview node afterselect event set the position using FIND on the bindingsource that is the datasource of the datagrid.

HTH

TREE_PIC.GIF


TREE_LIST.GIF
 
Here's what I did in the end:

VB.NET:
 public void LoadReports()
    {
      reportsTableAdapter.Fill(realDS.Reports, Universe.UserFlag);
      
      reportsTreeView.BeginUpdate();

      RealDS.ReportsRow ro;

      for(int i = 0; i < reportsBindingSource.List.Count; i++) {
        ro = (reportsBindingSource.List[i] as DataRowView).Row as RealDS.ReportsRow;

        //if this report group is already in the tree
        if(!rootNode().ContainsKey(ro.REPORT_GROUP)) {
          rootNode().Add(ro.REPORT_GROUP, ro.REPORT_GROUP);
        }


        TreeNode tn = new TreeNode();
        tn.Text = ro.DISPLAY_NAME;
        tn.Tag = i;
        groupNode(ro.REPORT_GROUP).Add(tn);

      }
      reportsTreeView.EndUpdate();
    }

    private void tvReportsTree_AfterSelect(object sender, TreeViewEventArgs e)
    {
      if(e.Node.Tag != null && e.Node.Tag is int) {
        reportsBindingSource.Position = (int)(e.Node.Tag);
      } else {
        reportsBindingSource.Position = -1;
      }
          
    }

yep.. it's C# but easily translated if needed. I iterate the bindingsource list and record the positions instead.. there isnt any sorting or list mutating going on, so its reasonably safe to do
 
Good to see it working

Great you got it to work. Nice to have several choices implementing workarounds to TreeView non binding capability.

How did you get the tabs and indents to show in your source code post???

Found an article to get the key back into treeview too http://support.microsoft.com/kb/311318

I just like tag because it so non specific and flexible. Very cool to see an alternate though. I will have to try that out.

Here would be vb equivalent
'----------------------------------------------------------------
' Converted from C# to VB .NET using CSharpToVBConverter(1.2).
' Developed by: Kamal Patel (http://www.KamalPatel.net)
'----------------------------------------------------------------
PublicSub LoadReports()
reportsTableAdapter.Fill(realDS.Reports, Universe.UserFlag)
reportsTreeView.BeginUpdate()
Dim ro As RealDS.ReportsRow
Dim i AsInteger
For i = 0 To reportsBindingSource.List.Count - 1 Step i + 1
ro = CType(reportsBindingSource.List(i) , DataRowView).Row as RealDS.ReportsRow
'if this report group is already in the tree
IfNot rootNode().ContainsKey(ro.REPORT_GROUP) Then
rootNode().Add(ro.REPORT_GROUP, ro.REPORT_GROUP)
EndIf

Dim tn As TreeNode = New TreeNode()
tn.Text = ro.DISPLAY_NAME
tn.Tag = i
groupNode(ro.REPORT_GROUP).Add(tn)
Next
reportsTreeView.EndUpdate()
EndSub
PrivateSub tvReportsTree_AfterSelect(ByVal sender AsObject, ByVal e As TreeViewEventArgs)
IfTypeOf e.Node.Tag <> NothingAnd e.Node.Tag IsIntegerThen
reportsBindingSource.Position = CType((e.Node.Tag), Integer)
Else
reportsBindingSource.Position = -1
EndIf
EndSub
 
Great you got it to work. Nice to have several choices implementing workarounds to TreeView non binding capability.

How did you get the tabs and indents to show in your source code post???

Found an article to get the key back into treeview too http://support.microsoft.com/kb/311318

The article mentions key based access to a treeview and how to implement it. This confused me because as far as i was aware, it was already keyed by way of the Nodes property being a TreeNodeCollection:

treeview.Nodes["key"] //returns a node


There are two things that are not explained in my code:
rootNode() method
groupNodes(string) method

these are simply:
VB.NET:
Function rootNode() as TreeNodeCollection
  Return treeview.Nodes
End Function
VB.NET:
Function groupNode(s as string) as TreeNodeCollection
  Return treeview.Nodes(s).Nodes
End Function

This allows a 1-level deep tree with aliased access.

I just like tag because it so non specific and flexible. Very cool to see an alternate though. I will have to try that out.
I use tag here too, to store an int. If I had to store more data I would either use an object array (simple) or a custom mini-class

Here would be vb equivalent
(broken code)

There are 2 things you need to do when posting code.

First, you MUST put the editor into basic mode by clicking
switchmode.gif
button in the TOP RIGHT of the editor box.

Note this is NOT the
removeformat.gif
button in the top left



Click it once and wait. The edit window turns from pale blue grey to bright white and all formatting is hidden (not wysiwyg)

click the
code.gif
code button and the word CODE appears surrounded in [ brackets ]


Paste the code

click the
code.gif
code button again..


If you dont put the editor in basic mode, then all syntax highlighted words appear slammed together:
PublicSub
EndFunction
IfTypeOf e.Node.Tag <> NothingAnd e.Node.Tag IsIntegerThen


etc - this breaks the code and makes it impossible for another user to paste..

 
Thanks for posting tips. Just what I needed!

Hi thanks for the posting tips. That exactly what I needed.

Sorry, when you said "iterate" and spoke of treeview I had a flashback to the days when I could, without recursion, truly iterate all the nodes in the treeview collection. It was painful to remember my past as being easier than the current.

So I am thinking "why is L1 allowed to repeatedly be a key" and the answer is because each node is its own collection of child nodes
VB.NET:
 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.TreeView1.Nodes.Add("Root", "Root")

        'Dim oNode As TreeNode = New TreeNode("Level1")
        Me.TreeView1.Nodes.Add("L1", "Level1")
        Me.TreeView1.Nodes.Add("L2", "Level2")
        Me.TreeView1.Nodes.Add("L3", "Level3")

        Dim oNode1 As TreeNode = Me.TreeView1.Nodes("L1")
        oNode1.Nodes.Add("L1", "Level1 Child 1")
        oNode1.Nodes.Add("L2", "Level1 Child 2")

        Dim oNode2 As TreeNode = Me.TreeView1.Nodes("L2")
        oNode2.Nodes.Add("L1", "Level2 Child 1")
        oNode2.Nodes.Add("L2", "Level2 Child 2")

        Dim oNode3 As TreeNode = Me.TreeView1.Nodes("L3")
        oNode3.Nodes.Add("L1", "Level3 Child 1")
        oNode3.Nodes.Add("L2", "Level3 Child 2")

        Me.txtNodeRootLevel.Text = Me.TreeView1.Nodes("L1").Text
        Me.txtNodeNonRoot.Text = Me.TreeView1.Nodes("L1").Nodes("L1").Text

    End Sub
But as I understand currently, each node is the parent of a node collection. So unless you know what level and what node, iterating is not practical except in single level scenarios as you described.

This is the iterate pattern I use now http://msdn2.microsoft.com/en-us/library/wwc698z7(VS.80).aspx and it works.

I hadn't used the link I sent you but in trying it out it only allows for iterating as well and not [key] access (darn).

Ultimately the [key] property for me would be unique to the treeview and not the node collection. I could be wrong but this has been frustrating in the past.

At any rate...great again to see your solution and it working for you. Thanks for sharing the code.
 
The key of a Treenode is its Name property. This is new in .Net 2.0. It can be set for the node instance before adding it to Nodes or by using the Nodes.Add method overload that sets both key and text. The Nodes(key) item access only current collection level, but Nodes.Find(key, bSearchChilds) method also use Name key and returns an array of found nodes by key from current and any child node collection.
 
Back
Top