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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 13:45:15