Link to home
Start Free TrialLog in
Avatar of janmarini
janmarini

asked on

TreeView: How to return to selected node



Hi,

I am working with a VB.net application and am implementing a treeview control to load other forms.  The form that contains the control populates the treeview from a DB table on the form load event, and all the nodes are collapsed (by default).  This is fine for the first time the form is loaded, but I need a way to return to it's previous state (showing the selected node) when the user selects 'back' from the form that was loaded from the selected node.  Can this be done?

Thanks,
Jan

Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Sure...

What you can do is store the selected node in the tag property of the form that is opened.  Then when the "back" button is pushed, you can raise a custom event that will pass the selected node back to the main form.

Something like this:

' -----------------------------------------------
' Secondary Form opened from TreeView
' -----------------------------------------------
Public Class Form2
    Inherits System.Windows.Forms.Form

    Public Event frmBack(ByVal selectedNode As TreeNode)  ' <--- Your custom "back" event

    Private Sub btnBack_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBack.Click
        If Not (Me.Tag Is Nothing) Then
            RaiseEvent frmBack(Me.Tag) ' <--- raise the event, passing the selected node back to the main form
            Me.Close()
        End If
    End Sub
End Class

' -----------------------------------------------
' Main Form with TreeView
' -----------------------------------------------
    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        ' open the appropriate form...however you do it
        Dim f2 As New Form2
        f2.Tag = TreeView1.SelectedNode ' <--- put the selected node in the new forms tag property
        AddHandler f2.frmBack, AddressOf backEvent_frmBack ' <--- Add a handler so we can trap the "back" button event
        f2.Show()
    End Sub

    Private Sub backEvent_frmBack(ByVal selectedNode As System.Windows.Forms.TreeNode)
        ' one of the "back" buttons has been pushed
        ' make the node passed back in the current one and expand it
        TreeView1.SelectedNode = selectedNode
        TreeView1.SelectedNode.Expand()
    End Sub
Avatar of holli
holli

put the property "FullPath" of all expanded nodes into a collection or array.
put the "FullPath" of the selected node in a string variable.

while populating the treeview a second time, create the node and check if its "FullPath" is in the collection. if so, expand that node.
when finished get the node whichs "FullPath" you stored in the string variable and set its "Selected"-Property to true.

holli
Avatar of janmarini

ASKER

Thanks for your help both of you.  

I've been trying all day to try to get either solution to work for me, but haven't yet been successfull.  With the first solution I am having trouble with the statement -  AddHandler f2[replaced w/ my form].frmBack, AddressOf backEvent_frmBack - specifically the 'AddressOf backEvent_frmBack' part, something to do with the object (it was a while back and I don't recall the specific error message).  Also, when trying this out I think I may have over-simplified my original request (didn't want to scare folks away :-), my app is pretty complex and will either call a new form or load a report in the Crystal Report Viewer - my mention of a 'back' button was for an example - thought if I could figure out how to do that, the rest would follow.  Not happening yet.

I had trouble with the second recommendation as well.  Do you have a code snippet that might point me in the right direction?  I tried a few things and couldn't get it to work.  I may just need a fresh perspective, I've been at this since 4AM - and I am facing an urgent need to implement the tree control in my application. (Funny how things always seem to be needed yesterday after months of inactivity).

The worst part is is that I am a newbie with the VB.net version of the TreeView control, so everything is new and nothing has been accomplished with ease ::sigh::

I thought I would simplify my task by storing the Selected.Node into a global variable, then when the primary form re-loads to find that node and re-select it.  However, I am now stuck on the recursion - can't get things to go further than the first level of nodes.  Any advice here would be greatly appreciated - I'll even open up a new topic and award 500 points separately because I know that there will be others who are struggling with this situation as well, I searched high and low for the answers - but VB.net solutions are scarce (even after 3+ years!), and the VB.6 solutions are misleading (LOL - sometimes I really miss that ol' VB 6).

    Dim testnode As TreeNode = TreeView1.Nodes(0)
    For Each newNode In testnode.Nodes
        If Trim(newNode.Text) = "THE TEXT OF THE NODE" Then TreeView1.SelectedNode = newNode
    Next

**Need to figure out how to include the children/grandchildren these nodes might have**

For the full picture, my primary form load code thus far is :
NOTES:  (builds the treeview from SQL Server DB) (FYI: walkthrough code not yet cleaned up)

#Region "Form Events"
    Private Sub frmSwitchboard_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Try
           
                'set up TreeView
                Dim root As TreeNodeCollection = TreeView1.Nodes
                Dim newNode As TreeNode
                Dim ParentID As Integer
                Dim prevParentID As Integer
                Dim i, j, k As Integer '***Clean up for final
                root.Clear()

                'Get Data and populate TreeView
                Dim sqlstatement As String
                Dim a, b, c, d, f '***step debug - eliminate in final version
                sqlstatement = "SELECT * FROM ReportNodes WHERE ParentID = 0 ORDER BY ID, SequenceID"
                Dim strTemp As String = ""
                strTemp = GetConnectionString("Assessor")
                Dim sqlConn As SqlConnection = New SqlConnection(strTemp)
                sqlConn.Open()
                Dim cmdSQL As SqlCommand = New SqlCommand(sqlstatement, sqlConn)
                Dim dr As SqlDataReader = cmdSQL.ExecuteReader()

                Do While dr.Read
                 
                    newNode = TreeView1.Nodes.Add(dr.Item(1)) 'Add Parent to root
                    newNode.ImageIndex = 0
                    'Get Children
                    sqlstatement = "SELECT * FROM ReportNodes WHERE ParentID = " & (dr.Item(0)) & " ORDER BY NodeLevel, SequenceID"
                    sqlDS.Clear()
                    GetDataSet(sqlstatement, "Assessor", "Children")
                    Dim tbl As DataTable = sqlDS.Tables("Children")
                    Dim row As DataRow = tbl.Rows(0)
                    row = tbl.Rows(0)
                    a = tbl.Rows.Count
                    For i = 0 To tbl.Rows.Count - 1
                        row = tbl.Rows(i)
                        a = row("NodeName")
                        If i > 0 And row("NodeLevel") > 0 Then
                            newNode = newNode.Parent.Parent
                            newNode = newNode.Nodes.Add(row("NodeName"))
                        Else
                            If row("NodeLevel") > 0 Then
                                newNode = newNode.Nodes.Add(row("NodeName"))
                            Else
                                newNode.Nodes.Add(row("NodeName"))
                            End If
                        End If
                        sqlstatement = "SELECT * FROM ReportNodes WHERE ParentID = " & (row("ID")) & " ORDER BY NodeLevel, SequenceID"
                        GetDataSet(sqlstatement, "Assessor", "Child")
                        Dim tbl2 As DataTable = sqlDS.Tables("Child")
                        If tbl2.Rows.Count > 0 Then
                            Dim row2 As DataRow = tbl2.Rows(0)
                            row2 = tbl2.Rows(0)
                            For j = 0 To tbl2.Rows.Count - 1
                                row2 = tbl2.Rows(j)
                                a = row2("NodeName")
                                b = row2("NodeLevel")
                                If j > 0 Then
                                    newNode = newNode.Parent
                                    newNode = newNode.Nodes.Add(row2("NodeName"))
                                Else
                                    newNode = newNode.Nodes.Add(row2("NodeName"))
                                End If
                                sqlstatement = "SELECT * FROM ReportNodes WHERE ParentID = " & (row2("ID")) & " ORDER BY NodeLevel, SequenceID"
                                GetDataSet(sqlstatement, "Assessor", "GrandChildren")
                                Dim tbl3 As DataTable = sqlDS.Tables("GrandChildren")
                                If tbl3.Rows.Count > 0 Then
                                    Dim row3 As DataRow = tbl3.Rows(0)
                                    row3 = tbl3.Rows(0)
                                    For k = 0 To tbl3.Rows.Count - 1
                                        row3 = tbl3.Rows(k)
                                        a = row3("NodeName")
                                        b = row3("NodeLevel")
                                        newNode.Nodes.Add(row3("NodeName"))
                                    Next k
                                    sqlDS.Tables("GrandChildren").Clear()
                                End If
                            Next j
                        End If
                        sqlDS.Tables("Child").Clear()
                        sqlDS.Tables("GrandChildren").Clear()
                    Next i
                Loop
            dr.Close()

'***HERE IS WHERE I WOULD LIKE TO LEARN HOW TO GET TO THE SUBORDINATE NODES
            Dim testnode As TreeNode = TreeView1.Nodes(0)
            For Each newNode In testnode.Nodes
                If Trim(newNode.Text) = "THE TEXT OF THE NODE" Then TreeView1.SelectedNode = newNode
            Next
'***
        Catch ex As System.Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
        End Try
    End Sub

#End Region

Private Sub TreeView1_AfterSelect(ByVal sender As System.Object, _
    ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterSelect
        ' Determine by checking Text property.
        'MessageBox.Show("AfterSelect" & e.Node.Text & " " & e.Node.Index)
         Try
           
Select Case Trim(TreeView1.SelectedNode.Text
.
.
.
   Case "A-3b. Apartment Complexes"
                    glbReport = "SA_ER_APT"
                    Dim frm As New frmReportEngine()
                    Me.Hide()
                    frm.ShowDialog()
    Case Else
End Select

'***HERE IS WHERE I TRIED STORING THE SELECTED NODE TO BE USED LATER
            'glbSelectedNode = TreeView1.SelectedNode
            'b = TreeView1.SelectedNode.Text
'***
        Catch ex As System.Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
        End Try
    End Sub
In this line:

    AddHandler f2.frmBack, AddressOf backEvent_frmBack

you are correct in replacing f2 with your form name.  frmBack is the name of the event you have declared that each form must declare.  The AddressOf part points to the name of the subroutine that will handle the event, usually in the same class (but not necessarily).  It must have the same parameter signature as the event you are handling.

~IM
ASKER CERTIFIED SOLUTION
Avatar of holli
holli

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks Holli,

Your solution worked perfectly.   It is such a relief to have this done!  I really appreciate your help.

Thanks also IM, although I didn't get a chance to further explore your solution after I got things to work, it is really good to know that there are alternatives.  I am sure this is going to help someone in the future.  I wish I could award you some points too!