You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何自定义AdvancedTreeView的OnDrawNode重写方法从未被触发?

问题分析与解决方案

你的核心问题是你创建了AdvancedTreeView的实例,但从未将它添加到窗体的控件集合中——设计器里的TreeView是原生的TreeView控件,和你的自定义类完全无关,所以自然不会触发你重写的OnDrawNode方法。

步骤1:让窗体使用自定义的AdvancedTreeView

有两种方式可以快速解决这个问题:

方式一:通过代码直接添加(快速测试)

修改Form1的构造函数,把自定义控件实例添加到窗体上:

public Form1()
{
    InitializeComponent();
    // 可选:移除设计器添加的原生TreeView(如果不需要的话)
    // treeView1.Dispose();
    // treeView1 = null;

    // 创建自定义控件并配置
    AdvancedTreeView atv = new AdvancedTreeView();
    atv.Dock = DockStyle.Fill; // 让控件填满窗体
    atv.Nodes.Add("根节点");
    atv.Nodes[0].Nodes.Add("子节点");
    // 关键:将自定义控件添加到窗体的控件集合
    this.Controls.Add(atv);
}

方式二:在设计器中添加(更适合后续可视化设计)

  1. 先编译你的项目,让AdvancedTreeView类自动出现在Visual Studio的工具箱中
  2. 从工具箱拖放AdvancedTreeView控件到Form1上,替换原来的原生TreeView
  3. 可以直接在设计器中给这个自定义控件添加根节点和子节点,无需手动写代码

步骤2:修复其他潜在问题

除了核心的控件未添加问题,你的代码还有几个需要调整的地方,避免后续报错或效果不符合预期:

  • 图标初始化逻辑错误:FillPolygonPoint里创建Bitmap的方式有问题,而且依赖Form的Paint事件触发,很容易导致GetIcon拿到null。可以改为在自定义控件的构造函数中直接初始化图标:
public AdvancedTreeView()
{
    DrawMode = TreeViewDrawMode.OwnerDrawAll;
    ShowLines = false;
    AlternateBackColor = BackColor;
    // 初始化折叠状态的图标(示例:绘制向右箭头)
    myimage = new Bitmap(10,10);
    using (Graphics g = Graphics.FromImage(myimage))
    {
        g.Clear(Color.Transparent);
        g.DrawLines(Pens.Black, new Point[] { new Point(2,3), new Point(8,7), new Point(2,11) });
    }
}
  • OnDrawNode绘制顺序优化:你原来先调用base.OnDrawNode(e)再绘制背景,会导致原生绘制的内容被背景覆盖。调整顺序后效果更符合预期:
protected override void OnDrawNode(DrawTreeNodeEventArgs e)
{
    // 1. 先绘制行背景
    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));
    }
    // 2. 绘制展开/折叠图标
    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);
    }
    // 3. 绘制节点文本
    TextRenderer.DrawText(e.Graphics, e.Node.Text, Font, e.Bounds, ForeColor);
    // 4. 绘制选中焦点框
    if ((e.State & TreeNodeStates.Selected) != 0)
        ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds);
    
    // 不需要调用base.OnDrawNode,因为我们已经手动完成了所有绘制
    // base.OnDrawNode(e);
}

完成这些修改后,你的自定义TreeView就能正常触发OnDrawNode方法,实现交替行背景、自定义图标等效果了。

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:48:09