I am working with a treeview in VB with OwnerDrawText as my draw mode. I have handled Me.DrawNode
in my treeview to allow me to have highlight specific items (ie keep the last node highlighted and so on). I saw the the drawnode was being call and tried setting all of there backgrounds to a custom color buy doing this
Public Class Form1
Private nodelist As New List(Of TreeNode)
Public Sub New()
InitializeComponent()
TreeView1.Nodes.AddRange(New TreeNode() {
New TreeNode("Text of Node 0") With {.Name = "Node0"},
New TreeNode("Text of Node 1") With {.Name = "Node1"},
New TreeNode("Text of Node 2") With {.Name = "Node2"},
New TreeNode("Text of Node 3") With {.Name = "Node3"},
New TreeNode("Text of Node 4") With {.Name = "Node4"}
})
End Sub
Private Sub myTreeView_DrawNode(ByVal sender As Object, ByVal e As DrawTreeNodeEventArgs) Handles TreeView1.DrawNode
Console.WriteLine(e.Node.Text & " Rewritten")
' Draw the background and node text for a selected node.
If nodelist.Contains(e.Node) Then
e.Graphics.FillRectangle(New SolidBrush(Color.Chartreuse), e.Bounds)
TextRenderer.DrawText(e.Graphics, e.Node.Text, e.Node.NodeFont, e.Bounds,
Color.Black, Color.Empty,
TextFormatFlags.VerticalCenter)
Else
e.Graphics.FillRectangle(New SolidBrush(Color.Black), e.Bounds)
TextRenderer.DrawText(e.Graphics, e.Node.Text, e.Node.NodeFont, e.Bounds,
Color.White, Color.Empty,
TextFormatFlags.VerticalCenter)
End If
End Sub
Private Sub myTreeView_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles TreeView1.MouseDown
Console.WriteLine("Clicked")
Dim clickedNode As TreeNode = TreeView1.GetNodeAt(e.X, e.Y)
nodelist.Add(clickedNode)
If nodelist.Count > 3 Then
nodelist.RemoveAt(0)
End If
TreeView1.SelectedNode = clickedNode
End Sub
End Class
This code is supposed to highlight the last three selected nodes. However, if you click all the node, from 0 to 5, you will see it highlights everything. Then if you select node 2 you will see that all Nodes are redrawn (Console.WriteLine
shown this), which I assume would mean that Node 1 and 2 should be lose the highlight Color, but they don't.
The drawing part is correct, even though it can be simplified: the same methods can be used for both the background and the Text rendering, to DRY up the code.
The logic in the MouseDown event needs to be partially refactored, so the Nodes that are selected and unselected are actually added and removed from the collection of Nodes, the nodelist
Field.
The TreeView also needs to be notified of the change, calling its Invalidate()
method, so the Control can redraw the new selection of Nodes (Invalidate()
causes the Control to repaint itself, raising its Paint
or a similar, related, event: the DrawNode
event, in this case).
Simplified drawing method:
► Note: Here, I'm using the e.Node.Bounds
as the bounding rectangle for both the background and the Text of the Node. e.Bounds
can be used instead, if the rectangle seems too tight in the actual implementation. To be tested (it can be considered a matter of preference in this case).
Private Sub TreeView1_DrawNode(sender As Object, e As DrawTreeNodeEventArgs) Handles TreeView1.DrawNode
Console.WriteLine(e.Node.Text & " Rewritten")
Dim backColor As Color = Color.Black
Dim foreColor As Color = Color.White
If nodelist.Contains(e.Node) Then
backColor = Color.Chartreuse
foreColor = Color.Black
End If
e.Graphics.FillRectangle(New SolidBrush(backColor), e.Node.Bounds)
TextRenderer.DrawText(e.Graphics, e.Node.Text, e.Node.NodeFont, e.Node.Bounds,
foreColor, Color.Transparent, TextFormatFlags.VerticalCenter)
End Sub
The MouseDown event adds the currently selected node to the nodelist
collection if it's not already there, otherwise the node is removed from the collection.
Another condition is verified before the selected Node can be added to the collection: the collection cannot contain more than 4 items; if the collection is already full, the selected Node is not added.
Private Sub myTreeView_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles TreeView1.MouseDown
Dim clickedNode As TreeNode = TreeView1.GetNodeAt(e.X, e.Y)
If nodelist.Contains(clickedNode) Then
nodelist.Remove(clickedNode)
Else
If nodelist.Count < 4 Then
nodelist.Add(clickedNode)
TreeView1.SelectedNode = clickedNode
End If
End If
TreeView1.Invalidate()
End Sub