I have a treeview with four levels; parent, child, grandchild, great-grandchild. My selectednode is at the grandchild level.
What I'm trying to do is to create a new "Treeview" at the grandchild - NO, I dont wnat to create a new node to the "selectednode" (grandchild). So it should be somelike this:
parent
child
grandchild (New TreeView) PARENT which was grandchild
great-grandchild child
great-grandchild child
grandchild grandchild
It would be similar to a parent table where the mother and father went off and had new childern with a different spouse other than the spouse of there existing children.
Private Sub PopulateRootLevel()
' query to find first round of parent
PopulateNodes(dt, JCATreeView.Nodes)
End Sub
Private Sub PopulateNodes(ByVal dt As DataTable, ByVal nodes As TreeNodeCollection)
For Each dr As DataRow In dt.Rows
Dim tn As New TreeNode()
tn.Text = dr("TITLE").ToString()
tn.Value = dr("Parent_ID").ToString()
nodes.Add(tn)
'If node has child nodes, then enable on-demand populating
tn.PopulateOnDemand = (CInt(dr("childnodecount")) > 0)
Next
End Sub
Private Sub PopulateSubLevel(ByVal parentid As Integer, ByVal parentNode As TreeNode)
' query to find children of parent with child node count of parent
da.Fill(dt)
PopulateNodes(dt, parentNode.ChildNodes)
End Sub
Protected Sub TreeView1_TreeNodePopulate(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.TreeNodeEventArgs) Handles TreeView1.TreeNodePopulate
' add a test to determine if this is from TreeView1 or Sub_TreeView1
PopulateSubLevel(CInt(e.Node.Value), e.Node)
End Sub
Protected Sub TreeView1_SelectedNodeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles TreeView1.SelectedNodeChanged
Dim selected_parent_id As Integer = sender.SelectedNode.value
Parent_to_NEW_TREEVIEW_PopulateSubLevel(selected_parent_id, sender.SelectedNode)
End Sub
Private Sub Sub_TreeView1_PopulateSubLevel(ByVal parent_id As Integer, ByVal parentNode As TreeNode)
' Query to get new children of parents
da.Fill(dt2)
Sub_TreeView1_PopulateNodes(dt2, parentNode.ChildNodes)
End Sub
Private Sub Sub_TreeView1_PopulateNodes(ByVal dt As DataTable, ByVal nodes As TreeNodeCollection)
For Each dr As DataRow In dt.Rows
Dim tn As TreeNode = New TreeNode()
'tn = parentBCNode.Nodes.Add("NEW_PARENT_TREEVIEW")
' query to get child on the new parent treeview
tn.Text = dr("New parent title").ToString()
tn.Value = dr("New_parent_ID").ToString()
nodes.Add(tn)
'If node has child nodes, then enable on-demand populating
tn.PopulateOnDemand = (CInt(dr("childnodecount")) > 0)
Next
End Sub
You can't do that.
A TreeView can not have as one of its child nodes another TreeView control. The only thing you can do is assign the TreeView to the tag property of a TreeNode, but that will not be displayed (obviously).
I don't understand why you would want to do that, unless you want a different drawing behavior for that grand-child sub-tree.
You can make use of the treeNode.Level property to find out at which level that node is. And again you can create a custom object(that has all your required information) and store it in the treeNode.Tag property.
Related
I am using Visual Basic .NET 2013 and I want to know which child nodes are checked in a treeview. I don't check parent nodes because the checkboxes are only in child nodes (I have disabled checkboxes in parent nodes, so they don't appear).
At the moment I am using one solution I found:
Private Sub TreeView1_AfterCheck(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterCheck
Dim childNodeCK As TreeNode = e.Node
If childNodeCK.Checked = True Then
If e.Node.Parent Is Nothing = False Then 'detects a Child Node
TextBox1.Text = TextBox1.Text & childNodeCK.Text
MessageBox.Show("Checked: " & childNodeCK.Text)
End If
End If
If childNodeCK.Checked = False Then
If e.Node.Parent Is Nothing = False Then
MessageBox.Show("Unchecked: " & childNodeCK.Text)
End If
End If
End Sub
But I want to know if there is another solution, something like this (the following code doesn't show anything because when I click a button to run it, nothing happens):
For Each childNode As System.Windows.Forms.TreeNode In TreeView1.Nodes
If childNode.Checked = True Then
MessageBox.Show(childNode.Text)
End If
Next
because the idea is to click a button and obtain the name (text) of the child nodes that are checked at that moment. So I think I have to check one by one from the beginning to the end and if the child node is checked then execute some code.
To get all of the checked nodes, you would have to use a recursive function or a stacked list. I prefer the latter:
Private Function GetCheckedNodes() As List(Of TreeNode)
Dim result As New List(Of TreeNode)
'Get the root nodes
Dim nodes As New Stack(Of TreeNode)
For Each tn As TreeNode In TreeView1.Nodes
nodes.Push(tn)
Next
'Check each node and it's children
While nodes.Count > 0
Dim popNode As TreeNode = nodes.Pop
If popNode.Checked Then
result.Add(popNode)
End If
For Each tn As TreeNode In popNode.Nodes
nodes.Push(tn)
Next
End While
Return result
End Function
Then to use it:
For Each tn As TreeNode In GetCheckedNodes()
MessageBox.Show(tn.Text)
Next
I have Tree view that have 2 Root(Masters, Transactions) node and Each Root have 1 Child(See Tree view in Image)
Masters->Party master
Transactions->Order Acceptance
I want to Display frmPartymaster.vb form when clicking Party Master(child node)
and
Display frmorder.vb form when clicking Order Acceptance(child node)
I Tried Tree view After Select event(see below code)
Private Sub TreeView1_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterSelect
For Each node As TreeNode In Me.TreeView1.Nodes
GetChildren(node)
Next node
End Sub
Function GetChildren(ByVal parentNode As TreeNode) As List(Of String)
Dim nodes As List(Of String) = New List(Of String)
GetAllChildren(parentNode, nodes)
Return nodes
End Function
Sub GetAllChildren(ByVal parentNode As TreeNode, ByVal nodes As List(Of String))
For Each childNode As TreeNode In parentNode.Nodes
nodes.Add(childNode.Text)
GetAllChildren(childNode, nodes)
Next
End Sub
Above Code returns all childnode's names in Return nodes variable
Now I am Looking for
how to use nodes variable values
And how to show appropriate form when clicking child
node(I know child node haven't click event)
Tell me any other efficient way found instead of afterselect event
because it loop through all root node and child node each time
According to the code you provided, you are not even trying to instantiate another class depending on what node you have selected. All that is doing is adding nodes to a list, this is not needed...
This solution you can add any class where its type is Form.
There are a few ways this can be accomplished, but I just provided one way to do what you would like to achieve.
Imports System.Reflection
Public Class Form1
Private Const FORM_PARTY_MASTER As String = "frmPartyMaster"
Private Const FORM_ORDER As String = "frmorder"
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim mNode As New TreeNode With {.Text = "Masters"}
mNode.Nodes.Add(New TreeNode With {.Text = "Party Masters", .Tag = FORM_PARTY_MASTER})
Dim transNode As New TreeNode With {.Text = "Transaction"}
transNode.Nodes.Add(New TreeNode With {.Text = "Order/Acceptance", .Tag = FORM_ORDER})
TreeView1.Nodes.AddRange({mNode, transNode})
End Sub
Private Sub TreeView1_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterSelect
Dim obj As Form
Try
If e.Node.Tag IsNot Nothing Then
obj = CType(Activator.CreateInstance(Type.GetType("WindowsApplication5." & e.Node.Tag.ToString, False)), Form)
If obj IsNot Nothing Then
Using obj
obj.ShowDialog()
End Using
End If
End If
Catch ex As Exception
'handle your exception
End Try
End Sub
End Class
Explanation
Create some constants that would represent your forms.
The load routine was just to populate the data. You will notice I use the Tag property of the TreeNode, we will use this to get an instance of what form we would need.
The AfterSelect event is used. You will see how I create an instance of whatever control you would need; no case or if statements.
Make sure you change WindowsApplication5 to what your namespace would be.
Not too sure on how to get around this.
I am able to display the current selected node in a textbox (or richtextbox) by doing the following:
Private Sub TreeView1_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterSelect
RichTextBox1.Text = e.Node.Text
End Sub
However, I can't figure out a way of displaying all child nodes of the selected parent.
Would anyone be able to point me in the right direction?
You need what is called a recursive subroutine to drill down into the child nodes of each node to iterate through them:
Private Sub TreeView1_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterSelect
Dim myNode As TreeNode = e.Node
TextBox1.Text = myNode.Text
GetChildNodes(myNode)
End Sub
Sub GetChildNodes(tnode As TreeNode)
'Iterate through the child nodes of the node passed into this subroutine
For Each node As TreeNode In tnode.Nodes
TextBox1.Text += node.Text
'If the node passed into this subroutine contains child nodes,
'call the subroutine for each one of them
'If you only want to display one level deep, then comment out the
'IF statement.
If tnode.Nodes.Count > 0 Then GetChildNodes(node)
Next
End Sub
I have a menu item that appears when right clicking over a datagridview. From their the user hovers over a menuitem and a list of other menu items appears, once again this repeats. Giving soemthing like this.
---------
| FOO |---------
---------| BAR |------------
---------| FOOBAR |
------------
There is only to be an event (addressof) handled on the the 3rd tier. With that being said I need to grab the parent.name from FOOBAR and the parent.name of the said parent (grandparent).
Here is where I am at:
If currentMouseRow >= 0 AndAlso currentMouseColumn <= 1 Then
dataGridView_monitorMapping.Rows(currentMouseRow).Selected = True
mainMenu.MenuItems.Add(New MenuItem("Set Monitor(s) Settings"))
mainMenu.MenuItems.Add(New MenuItem("Sync Monitor Mapping View", AddressOf triggerSync))
'list avaliable priorites
For Each priorityRow As DataRow In priorityTypesDS.Tables(0).Rows
Dim rowPriortiyName As String = CStr(priorityRow("Priority"))
Dim subMenu_priorities_item As New MenuItem(rowPriortiyName)
mainMenu.MenuItems(0).MenuItems.Add(subMenu_priorities_item)
'list avaliable boards
For Each boardRow As DataRow In serviceBoardDS.Tables(0).Rows
Dim rowBoardName As String = CStr(boardRow("SvcBrd"))
Dim subMenu_boards_item As New MenuItem(rowBoardName)
subMenu_priorities_item.MenuItems.Add(subMenu_boards_item)
'list avaliable types based on board
If rowBoardName IsNot Nothing Then
Dim availableSvcTypes As DataSet = GetServiceTypes(_objhost, serviceTypes, rowBoardName)
For Each svcTypeRow As DataRow In availableSvcTypes.Tables(0).Rows
Dim rowSvcTypeName As String = CStr(svcTypeRow(1))
Dim subMenu_svcType_item As New MenuItem(rowSvcTypeName, AddressOf triggerSync)
subMenu_boards_item.MenuItems.Add(subMenu_svcType_item)
Next
End If
Next
Next
mainMenu.Show(dataGridView_monitorMapping, New Point(e.X, e.Y))
End If
And the event handler
Public Sub updateMultiRowSettingChange(ByVal Sender As System.Object, ByVal e As System.EventArgs)
'TODO | Handle selection from right click menu.
End Sub
Something like this should get you what you are looking for:
Public Sub updateMultiRowSettingChange(ByVal Sender As System.Object, ByVal e As System.EventArgs)
Dim item As MenuItem = CType(sender, MenuItem)
Dim parent As MenuItem = CType(item.Parent, MenuItem)
Dim grandparent As Menu = parent.Parent
End Sub
However, it may be simpler to set the tag on the menu item to whatever information you need to know where it's coming from, then you could just check item.Tag after you cast it to the MenuItem class.
I am trying to check all the childnodes under a parent node, the code I have so far only goes about 2-3 levels deep in the TreeView and I am looking to grab all nodes no matter how deep they are. Could someone shed some insight on this.
Below is the code:
Private Sub CheckChildNode(ByVal currNode As TreeNode)
'set the children check status to the same as the current node
Dim checkStatus As Boolean = currNode.Checked
For Each node As TreeNode In currNode.Nodes
node.Checked = checkStatus
CheckChildNode(node)
Next
End Sub
Private Sub CheckParentNode(ByVal currNode As TreeNode)
Dim parentNode As TreeNode = currNode.Parent
If parentNode Is Nothing Then Exit Sub
parentNode.Checked = True
For Each node As TreeNode In parentNode.Nodes
If Not node.Checked Then
parentNode.Checked = False
Exit For
End If
Next
CheckParentNode(parentNode)
End Sub
Private Sub treeview_AfterCheck(ByVal sender As System.Object, ByVal e As
System.Windows.Forms.TreeViewEventArgs) Handles treeview.AfterCheck
RemoveHandler treeview.AfterCheck, AddressOf treeview_AfterCheck
CheckChildNode(e.Node)
CheckParentNode(e.Node)
AddHandler treeview.AfterCheck, AddressOf treeview_AfterCheck
End Sub
In order to get all subnodes no matter how deep they are, you definitely need recursion.
That is, you take each direct child of a node and do the check for this node. And you also call the method to check subnodes for each child.
So here in Pseudocode.
node getParentNode(node child){
return child.parent
}
node checkNode(node n){
// perform check here for node n
if n is not valid {
return false!
}
// do children recursively
for each child in n.children{
// function calls itself!
checkNode(child)
}
}
Here's a recursion tutorial for vb.net. Here, here and here is you can find additional information.