С# WinForms выделяют treenode, когда treeview не имеет фокуса

Gretings.

Я создаю интерфейс для редактирования сценариев для игры. В основном он состоит из событий, которые имеют вложенные условия и действия. Итак, я планировал использовать два дерева - один для выбора события, а другой для выбора условия/действия внутри события для редактирования.

Теперь вы видите, что если я выбираю событие (в левом древовидной структуре), а затем пытаюсь выбрать что-то в правом дереве, левое дерево перестает показывать синий прямоугольник выделения. Это явно плохо, потому что теперь пользователь не знает, какое событие он редактирует!

Единственный способ, которым я нашел, чтобы сохранить некоторую информацию о том, что является текущим выбором, - это использовать SelectedImageIndex, но это только одно небольшое изображение, которое будет другим.

Есть ли другой способ выделить treenode, пока нет фокуса на древовидной структуре? Я знаю, что могу просто Graphics.DrawRectangle или что-то в этом роде, но я слышал, что этот рисунок должен быть выполнен в событии Paint, а treeview не имеет события рисования... Поэтому я думаю, если я нарисую его на событии потери фокуса, а затем перетащите форму вне экрана или что-то еще, оно будет "стерто"?

В любом случае, скажите, пожалуйста, если у вас есть идея (кроме использования отдельного значка для выбранного и не выбранного treenode)

Спасибо!

Ответ 1

То, что вы ищете, это свойство HideSelection на TreeView.

От MSDN:

Получает или задает значение, указывающее, будет ли выделенное дерево node оставаться выделенным, даже если древовидный вид потерял фокус.

Ссылка: http://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.hideselection.aspx

Код:

TreeView.HideSelection = false;

Ответ 2

Он по-прежнему отображается, но только в светло-сером цвете, который в зависимости от вашего экрана и текущей настройки может находиться рядом с видимым!

Переопределить событие OnDrawNode. Таким образом, вы создаете и новый класс (называете его "SpecialTreeView" ) наследованием от Microsoft TreeView, как class SpecialTreeView : TreeView. Затем вы добавляете следующее переопределение события:

protected override void OnDrawNode(DrawTreeNodeEventArgs e)
{
    TreeNodeStates treeState = e.State;
    Font treeFont = e.Node.NodeFont ?? e.Node.TreeView.Font;

    // Colors.
    Color foreColor = e.Node.ForeColor;
    string strDeselectedColor = @"#6B6E77", strSelectedColor = @"#94C7FC";
    Color selectedColor = System.Drawing.ColorTranslator.FromHtml(strSelectedColor);
    Color deselectedColor = System.Drawing.ColorTranslator.FromHtml(strDeselectedColor);

    // New brush.
    SolidBrush selectedTreeBrush = new SolidBrush(selectedColor);
    SolidBrush deselectedTreeBrush = new SolidBrush(deselectedColor);

    // Set default font color.
    if (foreColor == Color.Empty)
        foreColor = e.Node.TreeView.ForeColor;

    // Draw bounding box and fill.
    if (e.Node == e.Node.TreeView.SelectedNode)
    {
        // Use appropriate brush depending on if the tree has focus.
        if (this.Focused)
        {
            foreColor = SystemColors.HighlightText;
            e.Graphics.FillRectangle(selectedTreeBrush, e.Bounds);
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, foreColor, SystemColors.Highlight);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds,
                                         foreColor, TextFormatFlags.GlyphOverhangPadding);
        }
        else
        {
            foreColor = SystemColors.HighlightText;
            e.Graphics.FillRectangle(deselectedTreeBrush, e.Bounds);
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, foreColor, SystemColors.Highlight);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds,
                                         foreColor, TextFormatFlags.GlyphOverhangPadding);
        }
    }
    else
    {
        if ((e.State & TreeNodeStates.Hot) == TreeNodeStates.Hot)
        {
            e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, hotFont, e.Bounds,
                                         System.Drawing.Color.Black, TextFormatFlags.GlyphOverhangPadding);
        }
        else
        {
            e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
            TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds,
                                         foreColor, TextFormatFlags.GlyphOverhangPadding);
        }
    }
}

Скомпилируйте код, и вы увидите "SpecialTreeView" в вашем ящике инструментов в дизайнере. Замените TreeView на этот новый, используя одно и то же имя, и единственное, что будет отличаться, это цвета выбора. При выборе он будет selectedColor, если не выбран deselectedColor.

Надеюсь, это поможет.

Ответ 3

Быстрое решение:

Задайте свойства:

  • HideSelection = false;
  • DrawMode = TreeViewDrawMode.OwnerDrawText;

Затем в обработчике событий DrawNode просто выполните:

private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e) {
  e.DrawDefault = true;
}

В Windwos 7 это восстанавливает старый рендеринг, включая пунктирный прямоугольник вокруг выделения (который на самом деле выглядит немного устаревшим). Текст будет белым с фокусом, а черный - без фокуса. Фон остается синим и видимым.

Этот ответ не нов, другие также содержат эти шаги, но это минимально необходимый (по крайней мере, в Windows 7, не тестировал другие ОС).

Ответ 4

Не совсем идеальное решение, но довольно близко:

treeView.HideSelection = false;
treeView.DrawMode = TreeViewDrawMode.OwnerDrawText;
treeView.DrawNode += (o, e) =>
{
    if (!e.Node.TreeView.Focused && e.Node == e.Node.TreeView.SelectedNode)
    {
        Font treeFont = e.Node.NodeFont ?? e.Node.TreeView.Font;
        e.Graphics.FillRectangle(Brushes.Gray, e.Bounds);
        ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds, SystemColors.HighlightText, SystemColors.Highlight);
        TextRenderer.DrawText(e.Graphics, e.Node.Text, treeFont, e.Bounds, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding);
    }
    else
        e.DrawDefault = true;
};
treeView.MouseDown += (o, e) =>
{
    TreeNode node = treeView.GetNodeAt(e.X, e.Y);
    if (node != null && node.Bounds.Contains(e.X, e.Y))
        treeView.SelectedNode = node;
};

Ответ 5

Похож на предыдущий, но внешне больше похож на стандарт Win10:

treeView.HideSelection = false;
treeView.DrawMode = TreeViewDrawMode.OwnerDrawText;

treeView.DrawNode += (o, e) =>
{
    if (e.Node == e.Node.TreeView.SelectedNode)
    {
        Font font = e.Node.NodeFont ?? e.Node.TreeView.Font;
        Rectangle r = e.Bounds;
        r.Offset(0, 1);
        Brush brush = e.Node.TreeView.Focused ? SystemBrushes.Highlight : Brushes.Gray;
        e.Graphics.FillRectangle(brush, e.Bounds);
        TextRenderer.DrawText(e.Graphics, e.Node.Text, font, r, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding);
    }
    else
        e.DrawDefault = true;
};

treeView.MouseDown += (o, e) =>
{
    TreeNode node = treeView.GetNodeAt(e.Location);
    if (node != null && node.Bounds.Contains(e.Location)) treeView.SelectedNode = node;
};

Ответ 6

Нашел более простой способ:

  1. Установить TreeView.HideSelection = True
  2. Добавьте следующее в TreeView.AfterSelect-Callback:
    private void treeViewBenutzerverwaltung_AfterSelect(object sender, TreeViewEventArgs e)
    {
        // Select new node
        e.Node.BackColor = SystemColors.Highlight;
        e.Node.ForeColor = SystemColors.HighlightText;
        if (_lastSelectedNode != null)
        {
            // Deselect old node
            _lastSelectedNode.BackColor = SystemColors.Window;
            _lastSelectedNode.ForeColor = SystemColors.WindowText;
        }
        lastSelectedNode = e.Node;
    }