سؤال

Is there an easy way to have a selected TreeNode retain its SystemColors.Highlight BackColor while the TreeView doesn't have focus? Because even with HideSelection set to false, the selected BackColor is near impossible to see.

Selected TreeNode while TreeView has focus:

Focused

Selected TreeNode while TreeView does not have focus:

Unfocused

Thanks in advance.

EDIT: I'm aware i could set DrawMode to OwnerDrawAll and then add a custom DrawNode event. I did attempt this previously, the problem i have is i don't know how to go about drawing the TreeNode's corresponding ImageKey properly.

هل كانت مفيدة؟

المحلول 2

The solution, works like a charm:

public TreeNode previousSelectedNode = null;
private void treeView1_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
    treeView1.SelectedNode.BackColor = SystemColors.Highlight;
    treeView1.SelectedNode.ForeColor = Color.White;
    previousSelectedNode = treeView1.SelectedNode;
}

private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
    if(previousSelectedNode != null)
    {
        previousSelectedNode.BackColor = treeView1.BackColor;
        previousSelectedNode.ForeColor = treeView1.ForeColor;
    }
}

نصائح أخرى

If retaining the SystemColors.Highlight background color is all you wanted, then you don't need to set the TreeView's DrawMode property to TreeViewDrawMode.OwnerDrawAll. Setting it to TreeViewDrawMode.OwnerDrawText should be sufficient, thus you don't need to worry about drawing the TreeNode's corresponding ImageKey.

  1. Set the TreeView.DrawMode to TreeViewDrawMode.OwnerDrawText:

    treeView.DrawMode = TreeViewDrawMode.OwnerDrawText;
    
  2. Set the Treview.HideSelection to false, so that the node states will be kept as selected:

    treeView.HideSelection= false;
    
  3. Add DrawNode event handler to draw the background using SystemColors.Highlight color:

    private void treeView_DrawNode(object sender, DrawTreeNodeEventArgs e)
    {
      if (e.Node == null) return;
    
      // if treeview's HideSelection property is "True", 
      // this will always returns "False" on unfocused treeview
      var selected = (e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected;
      var unfocused = !e.Node.TreeView.Focused;
    
      // we need to do owner drawing only on a selected node
      // and when the treeview is unfocused, else let the OS do it for us
      if (selected && unfocused)
      {
        var font = e.Node.NodeFont ?? e.Node.TreeView.Font;
        e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds);
        TextRenderer.DrawText(e.Graphics, e.Node.Text, font, e.Bounds, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding);
      }
      else
      {
        e.DrawDefault = true;
      }
    }
    

I use this solution, and it's work better

private void treeView1_Enter(object sender, EventArgs e)
{
   if (treeView1.SelectedNode != null)
   {
       treeView1.SelectedNode.BackColor = Color.Empty;
       treeView1.SelectedNode.ForeColor = Color.Empty;
   }
}

private void treeView1_Leave(object sender, EventArgs e)
{
   if (treeView1.SelectedNode != null)
   {
       treeView1.SelectedNode.BackColor = SystemColors.Highlight;
       treeView1.SelectedNode.ForeColor = Color.White;
   }
}

EDIT

Based on this documentation,

The default is Color.Empty

So, in treeView1_Enter it's better to set the color like this

treeView1.SelectedNode.BackColor = Color.Empty;
treeView1.SelectedNode.ForeColor = Color.Empty;

Previous Answer

treeView1.SelectedNode.BackColor = treeView1.BackColor;
treeView1.SelectedNode.ForeColor = treeView1.ForeColor;

if you just need to highlight selected node when treeview goes out of focus then just use treeView.HideSelection = false;

Actually by default the selected node is highlighted but not visible so we just need to make HideSelection property to false.

Found this great solution here (MSDN)

Worked great for me, hope it'll help somebody else.

  1. Add a new class (file called MyTreeView.cs) to your project and paste the code shown below.
  2. Compile.
  3. Drop the new control called "MyTreeView" from the top of the toolbox onto your form.

You can customize it too, if you know what you are doing

using System;
using System.Drawing;
using System.Windows.Forms;



class MyTreeView : TreeView {
    public MyTreeView() {
        this.DrawMode = TreeViewDrawMode.OwnerDrawText;
    }
    protected override void OnDrawNode(DrawTreeNodeEventArgs e) {
        TreeNodeStates state = e.State;
        Font font = e.Node.NodeFont ?? e.Node.TreeView.Font;
        Color fore = e.Node.ForeColor;
        if (fore == Color.Empty) fore = e.Node.TreeView.ForeColor;
        if (e.Node == e.Node.TreeView.SelectedNode) {
            fore = SystemColors.HighlightText;
            e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds);
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, fore, SystemColors.Highlight);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, font, e.Bounds, fore, TextFormatFlags.GlyphOverhangPadding);
        }
        else {
            e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, font, e.Bounds, fore, TextFormatFlags.GlyphOverhangPadding);
        }
    }
}

this is the default behavior for the treeview. All you need to do to change it is override drawnode. There is another stack overflow answer that explains it better than I could here.

How to change background color of selected node in TreeView using TreeViewDrawMode.OwnerDrawAll?

Following code works even with programmatically selected nodes.

public TreeNode m_previousSelectedNode = null;
private void m_treeView_AfterSelect(object sender, TreeViewEventArgs e)
{
    if (m_previousSelectedNode != null)
    {
        m_previousSelectedNode.BackColor = m_treeView.BackColor;
        m_previousSelectedNode.ForeColor = m_treeView.ForeColor;
    }

    e.Node.BackColor = SystemColors.Highlight;
    e.Node.ForeColor = Color.White;

    m_previousSelectedNode = m_treeView.SelectedNode;
}

This variant of IronGeeks answer works for me and works with Bold Nodes:

Private Sub TreeView1_DrawNode(sender As Object, e As DrawTreeNodeEventArgs) Handles trvIdent.DrawNode
    Dim treeView = e.Node.TreeView
    Dim selected = (e.Node Is treeView.SelectedNode)
    Dim unfocused = Not treeView.Focused
    Dim font = If(e.Node.NodeFont IsNot Nothing, e.Node.NodeFont, treeView.Font)
    Dim textSize = e.Graphics.MeasureString(e.Node.Text, font)
    Dim bounds = New Rectangle(e.Bounds.X, e.Bounds.Y,
                               Convert.ToInt32(textSize.Width),
                               Math.Max(Convert.ToInt32(textSize.Height), e.Bounds.Height))

    e.DrawDefault = False

    If selected Then
        e.Graphics.FillRectangle(SystemBrushes.Highlight, bounds)
        e.Graphics.DrawString(e.Node.Text, font, SystemBrushes.HighlightText, bounds.Location)
    Else
        e.Graphics.FillRectangle(SystemBrushes.Window, bounds)
        e.Graphics.DrawString(e.Node.Text, font, SystemBrushes.WindowText, bounds.Location)
    End If
    'e.Graphics.DrawRectangle(Pens.Magenta, bounds)
End Sub

The main difference is that the custom drawing is done even if the TreeView is focused. And DrawString() is used instead of DrawText().

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top