【问题标题】:Why the code never reaching the override OnDrawNode method?为什么代码永远不会到达覆盖 OnDrawNode 方法?
【发布时间】:2019-07-19 20:45:32
【问题描述】:

在 form1 设计器中,我添加了一个树视图控件,并向其添加了一个根节点和一个子节点。并创建了绘画事件。

在form1代码中:

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。

【问题讨论】:

  • 因为在Form1_Paint 中,您调用了一个静态方法,它不知道OnDrawNode(). 您在ctor 中创建的avt 实例刚刚创建并可供使用ctor 结束时的 GC,然后 OnDrawNode() 将永远不会在已处置的对象上被调用,也永远不会看到 myimage 静态字段。一般来说,您应该避免使用 static 方法,但无论如何,在这种情况下,您还需要将 AdvancedTreeControl 放在 UI 中的某个位置:使用设计器创建它或使用类似于 this.Controls.Add(avt) 的东西手动添加它
  • 我知道我已经看过这个代码somewhere。 :)) 在您的表单构造函数中,您创建AdvancedTreeView 的本地实例,它的生命周期很短...... 1 行。相反,将AdvancedTreeView 拖放到设计器中的表单上(如果您构建项目,它必须出现在工具箱中)。如果它有效,我希望我的原始答案值得一票。 :))))
  • 您的myImage 仅在静态方法中设置。在构造函数中设置它,或者如果您想自己绘制它,只需删除该部分。
  • 我的意思是你应该在构造函数中初始化你的图像,这样它就不会为空。像myImage = new Bitmap(...) 这样的东西。或者 myImage = Resources.ArrowDown; 如果您向项目添加了资源。
  • 别着急,有时间我会写答案的。

标签: c# winforms


【解决方案1】:

所以这是旧答案中“原始”AdvancedTreeView 示例的更完整版本。

新成员是openedIconclosedIcon 字段、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), });
        }
    }
}

设置颜色和添加节点后的设计器:

在运行时:

仍然可以通过更改颜色时使颜色无效等来改进...

【讨论】:

  • 工作得很好。谢谢。
  • 出于某种原因,它仅更改了第二个根节点的背景颜色。我在设计器的集合中添加了两个根节点。两人都有孩子。第一个扩展它时,它不会仅在第二个根中变为浅蓝色。
  • 我现在尝试使用根节点,似乎只有第二个根节点和他的孩子有浅蓝色背景。其他的只有 DeepSkyBlue
  • “第一个扩展时,它不会仅在第二个根中变为浅蓝色。” - 因为它不是这样工作的。每个根节点颜色交替:GetTopNodeIndex(e.Node) & 1 对于偶数根节点为 0,对于奇数根节点为 1。如果您需要通过打开/关闭状态交替调整OnDrawNode 中的背景颜色e.Node.IsExpanded
  • 请将新问题作为新帖子而不是 cmets 提出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-29
  • 2015-01-09
  • 2022-11-26
  • 1970-01-01
相关资源
最近更新 更多