C#中TreeView用OwnerDrawText时无法修改Node.BackColor问题
TreeView OwnerDrawText模式下e.DrawDefault=true时无法修改节点BackColor的问题
我有一个包含TreeView控件(名为tv)的窗体,该控件设置为TreeViewDrawMode.OwnerDrawText并实现了自定义DrawNode事件处理程序。当前存在的问题是:通过e.DrawDefault = true交给系统绘制的节点,仅能修改ForeColor,无法修改BackColor;但将DrawMode改为Normal禁用自定义绘制后,节点的BackColor可正常修改。
示例代码如下:
using System.Drawing; using System.Collections.Generic; using System.Windows.Forms; namespace TreeViewEx { public partial class Form1 : Form { private bool DoColor = false; private List<TreeNode> ColoredNodes = new(); private Color myColor = SystemColors.HighlightText; private Color myBackColor = Color.Black; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { // tv is the TreeView control on Form1 tv.HideSelection = false; tv.DrawMode = TreeViewDrawMode.OwnerDrawText; tv.DrawNode += tv_DrawNode!; } private static Color GetContrastColor(Color color) { return (color.R * 0.299M) + (color.G * 0.587M) + (color.B * 0.114M) > 149 ? SystemColors.WindowText : SystemColors.Window; } private void ColorAncestors() { foreach (var anode in ColoredNodes) { anode.ForeColor = SystemColors.WindowText; anode.BackColor = SystemColors.Window; } ColoredNodes.Clear(); if (!DoColor) { return; } var node = tv.SelectedNode; while (node.Parent != null) { node = node.Parent; node.ForeColor = myColor; node.BackColor = myBackColor; ColoredNodes.Add(node); } } private void tv_DrawNode(object sender, DrawTreeNodeEventArgs e) { if (e.Node == null) return; var selected = (e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected; var unfocused = !e.Node.TreeView.Focused; if (selected && unfocused) { using var font = e.Node.NodeFont ?? e.Node.TreeView.Font; e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds); TextRenderer.DrawText(e.Graphics, e.Node.Text, font, e.Bounds, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding); } else { e.DrawDefault = true; } } // cbOwnerDraw is a checkbox on Form1 private void cbOwnerDraw_CheckedChanged(object sender, EventArgs e) { tv.DrawMode = cbOwnerDraw.Checked ? TreeViewDrawMode.OwnerDrawText : TreeViewDrawMode.Normal; } } }
注:为简洁起见,部分代码片段已省略,例如设置DoColor = true的逻辑。
问题原因
在TreeViewDrawMode.OwnerDrawText模式下,系统默认绘制逻辑并不会主动应用你设置的TreeNode.BackColor属性。该模式的设计定位是让开发者自定义文本的绘制逻辑,背景绘制的控制权并未完全交给系统——即使设置e.DrawDefault = true,系统也仅处理文本相关的渲染,会忽略自定义的BackColor值。
解决方案
需要在DrawNode事件中,针对非选中/非失焦的节点,手动绘制背景色和文本,而非完全依赖e.DrawDefault = true。修改后的tv_DrawNode方法如下:
private void tv_DrawNode(object sender, DrawTreeNodeEventArgs e) { if (e.Node == null) return; var selected = (e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected; var unfocused = !e.Node.TreeView.Focused; if (selected && unfocused) { using var font = e.Node.NodeFont ?? e.Node.TreeView.Font; e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds); TextRenderer.DrawText(e.Graphics, e.Node.Text, font, e.Bounds, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding); } else { // 手动绘制自定义背景色 if (e.Node.BackColor != SystemColors.Window) { using var backBrush = new SolidBrush(e.Node.BackColor); e.Graphics.FillRectangle(backBrush, e.Bounds); } // 手动绘制文本,使用节点的ForeColor using var font = e.Node.NodeFont ?? e.Node.TreeView.Font; TextRenderer.DrawText(e.Graphics, e.Node.Text, font, e.Bounds, e.Node.ForeColor, TextFormatFlags.GlyphOverhangPadding); } }
补充说明
- 上述代码中,先判断节点是否设置了非默认的BackColor,若是则手动填充背景,再绘制文本,确保ForeColor和BackColor都能正常生效。
- 如果希望保留系统默认的节点图标(展开/折叠箭头),可以先调用
e.DrawDefault = true,再叠加绘制背景和文本,但需注意绘制顺序:先让系统绘制默认内容,再覆盖背景和文本。
内容的提问来源于stack exchange,提问作者Steve Stover
相关产品推荐
相关产品推荐

