Почему код никогда не достигает метода переопределения OnDrawNode?

В дизайнере form1 я добавил элемент управления treeview и добавил к нему один корневой узел и один дочерний узел. И создал событие рисования.

В коде формы 1:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            AdvancedTreeView atv = new AdvancedTreeView();
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            AdvancedTreeView.FillPolygonPoint(e);
        }
    }
}

Класс AdvancedTreeView:

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

public class AdvancedTreeView : TreeView
{
    private static Image myimage;

    public AdvancedTreeView()
    {
        DrawMode = TreeViewDrawMode.OwnerDrawAll;
        ShowLines = false;
        AlternateBackColor = BackColor;
    }

    public Color AlternateBackColor { get; set; }

    protected override void OnDrawNode(DrawTreeNodeEventArgs e)
    {
        e.DrawDefault = true;
        base.OnDrawNode(e);

        // background
        Color backColor = (GetTopNodeIndex(e.Node) & 1) == 0 ? BackColor : AlternateBackColor;
        using (Brush b = new SolidBrush(backColor))
        {
            e.Graphics.FillRectangle(b, new Rectangle(0, e.Bounds.Top, ClientSize.Width, e.Bounds.Height));
        }

        // icon
        if (e.Node.Nodes.Count > 0)
        {

            Image icon = GetIcon(e.Node.IsExpanded); // TODO: true=down;false:right
            e.Graphics.DrawImage(icon, e.Bounds.Left - icon.Width - 3, e.Bounds.Top);
        }

        // text (due to OwnerDrawText mode, indenting of e.Bounds will be correct)
        TextRenderer.DrawText(e.Graphics, e.Node.Text, Font, e.Bounds, ForeColor);

        // indicate selection (if not by backColor):
        if ((e.State & TreeNodeStates.Selected) != 0)
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds);
    }

    private Image GetIcon(bool isExpanded)
    {
        return myimage;
    }

    private int GetTopNodeIndex(TreeNode node)
    {
        while (node.Parent != null)
            node = node.Parent;

        return Nodes.IndexOf(node);
    }

    public static void FillPolygonPoint(PaintEventArgs e)
    {

        // Create solid brush.
        SolidBrush blueBrush = new SolidBrush(Color.Blue);

        // Create points that define polygon.
        Point point1 = new Point(0, 0);
        Point point2 = new Point(20, 10);
        Point point3 = new Point(0, 20);

        Point[] curvePoints = { point1 , point2, point3 };

        // Draw polygon to screen.
        e.Graphics.FillPolygon(blueBrush, curvePoints);

        myimage = new Bitmap(10,10,e.Graphics);
    }
}

Доходит до строки в AdvancedTreeView :

DrawMode = TreeViewDrawMode.OwnerDrawAll;

Но он никогда не попадает в OnDrawNode. Я также пробовал TreeViewDrawMode.OwnerDrawText, но он никогда не попадал в OnDrawNode.

🤔 А знаете ли вы, что...
C# обладает сборщиком мусора, который автоматически управляет памятью, что снижает риск утечек памяти.


171
1

Ответ:

Решено

Итак, вот более полная версия «оригинального» AdvancedTreeView образца из старого ответа.

Новыми членами являются поля openedIcon и closedIcon, свойство ArrowColor и методы GetIcon/InitIcon.

public class AdvancedTreeView : TreeView
{
    private Bitmap openedIcon, closedIcon;

    public AdvancedTreeView()
    {
        DrawMode = TreeViewDrawMode.OwnerDrawText;
        ShowLines = false;
        AlternateBackColor = BackColor;
        ArrowColor = SystemColors.WindowText;
    }

    public Color AlternateBackColor { get; set; }
    public Color ArrowColor { get; set; }

    protected override void OnDrawNode(DrawTreeNodeEventArgs e)
    {
        // background
        Color backColor = (GetTopNodeIndex(e.Node) & 1) == 0 ? BackColor : AlternateBackColor;
        using (Brush b = new SolidBrush(backColor))
        {
            e.Graphics.FillRectangle(b, new Rectangle(0, e.Bounds.Top, ClientSize.Width, e.Bounds.Height));
        }

        // icon
        if (e.Node.Nodes.Count > 0)
        {
            Image icon = GetIcon(e.Node.IsExpanded);
            e.Graphics.DrawImage(icon, e.Bounds.Left - icon.Width - 3, e.Bounds.Top);
        }

        // text (due to OwnerDrawText mode, indenting of e.Bounds will be correct)
        TextRenderer.DrawText(e.Graphics, e.Node.Text, Font, e.Bounds, ForeColor);

        // indicate selection (if not by backColor):
        if ((e.State & TreeNodeStates.Selected) != 0)
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds);
    }

    private int GetTopNodeIndex(TreeNode node)
    {
        while (node.Parent != null)
            node = node.Parent;

        return Nodes.IndexOf(node);
    }

    private Image GetIcon(bool nodeIsExpanded)
    {
        if (openedIcon == null)
            InitIcons();
        return nodeIsExpanded ? openedIcon : closedIcon;
    }

    private void InitIcons()
    {
        openedIcon = new Bitmap(16, 16);
        closedIcon = new Bitmap(16, 16);
        using (Brush b = new SolidBrush(ArrowColor))
        {
            using (Graphics g = Graphics.FromImage(openedIcon))
                g.FillPolygon(b, new[] { new Point(0, 0), new Point(15, 0), new Point(8, 15), });
            using (Graphics g = Graphics.FromImage(closedIcon))
                g.FillPolygon(b, new[] { new Point(0, 0), new Point(15, 8), new Point(0, 15), });
        }
    }
}

Designer после настройки цветов и добавления узлов:

Во время выполнения:

Его все еще можно улучшить, аннулируя цвета при их изменении и так далее...