为何自定义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); }
方式二:在设计器中添加(更适合后续可视化设计)
- 先编译你的项目,让
AdvancedTreeView类自动出现在Visual Studio的工具箱中 - 从工具箱拖放
AdvancedTreeView控件到Form1上,替换原来的原生TreeView - 可以直接在设计器中给这个自定义控件添加根节点和子节点,无需手动写代码
步骤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
相关产品推荐
相关产品推荐

