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

如何禁用WinForms .NET中TreeView的文本选中高亮效果

解决WinForms自定义TreeView节点文本高亮问题(无需所有者绘制)

要移除鼠标点击节点时的文本高亮,且不使用所有者绘制模式,可通过以下两种简单方式实现:


方法1:设置控件为不可选中

直接禁用控件的选中能力,从根源上避免高亮行为。在自定义TreeView的构造函数中添加一行代码:

public CustomTreeView()
{
    // 原有代码保持不变
    this.HideSelection = false;
    this.ItemHeight = 30; 

    // 添加这行代码,禁用控件选中能力
    SetStyle(ControlStyles.Selectable, false);
}

设置ControlStyles.Selectable为false后,TreeView将无法获得焦点,也不会触发任何选中相关的视觉反馈,包括鼠标点击时的文本高亮。


方法2:拦截鼠标点击文本区域的事件

如果需要保留控件的选中能力(虽然你的代码里已经通过OnBeforeSelect取消了选中),可以在OnMouseDown中判断点击区域,当点击文本区域时阻止基类处理事件,避免高亮:

修改OnMouseDown方法:

protected override void OnMouseDown(MouseEventArgs e)
{
    TreeViewHitTestInfo hitTestInfo = HitTest(e.Location);
    if (hitTestInfo.Location == TreeViewHitTestLocations.Image)
    {
        // 原有图片点击处理逻辑不变
        TreeNode node = hitTestInfo.Node;
        if (node != null)
        {
            int currentState = GetEffectiveState(node);
            if (currentState == 1)
            {
                SetNodeChecked(node, false);
            }
            else
            {
                SetNodeChecked(node, true);
            }
            UpdateStateIndices(node);
        }
    }
    // 点击文本区域时,不调用基类方法,避免触发高亮
    else if (hitTestInfo.Location != TreeViewHitTestLocations.Text)
    {
        base.OnMouseDown(e);
    }
}

这样只有点击图片区域时执行你的逻辑,点击文本区域时不会触发基类的鼠标按下处理,也就不会出现文本高亮。


完整修改后的代码

以下是整合了方法1的完整自定义TreeView代码:

public class CustomTreeView : TreeView
{
    // 自定义复选框图片字段
    private Image _checkedImage = Properties.Resources.CheckIcon;
    private Image _uncheckedImage = Properties.Resources.UnCheckIcon;
    private Image _intermediateImage = Properties.Resources.IntermediateCheckIcon;
    private ImageList _imageList;

    public CustomTreeView()
    {
        this.CheckBoxes = false;

        _imageList = new ImageList();
        _imageList.ImageSize = new Size(26, 26);
        _imageList.Images.Add("Unchecked", _uncheckedImage);
        _imageList.Images.Add("Checked", _checkedImage);
        _imageList.Images.Add("Intermediate", _intermediateImage);
        this.ImageList = _imageList;

        this.Font = new Font("Gadugi", 12f);
        this.ForeColor = Color.DodgerBlue;
        this.BackColor = SystemColors.Control;
        this.BorderStyle = BorderStyle.None;
        this.Scrollable = true;

        this.ShowLines = false;
        this.ShowRootLines = false;
        this.ShowNodeToolTips = true;
        this.ShowPlusMinus = false;

        this.HideSelection = false;
        this.ItemHeight = 30; 

        // 添加禁用选中的样式
        SetStyle(ControlStyles.Selectable, false);
    }

    private int GetEffectiveState(TreeNode node)
    {
        if (node.Nodes.Count == 0)
        {
            return node.Checked ? 1 : 0;
        }
        else
        {
            bool allChecked = true;
            bool anyChecked = false;
            foreach (TreeNode child in node.Nodes)
            {
                int childState = GetEffectiveState(child);
                if (childState == 0)
                    allChecked = false;
                else if (childState == 1)
                    anyChecked = true;
                else
                {
                    allChecked = false;
                    anyChecked = true;
                }
            }
            if (allChecked)
                return 1; 
            else if (anyChecked)
                return 2; 
            else
                return 0; 
        }
    }

    private void UpdateStateImageIndex(TreeNode node)
    {
        node.ImageIndex = GetEffectiveState(node); 
        node.SelectedImageIndex = node.ImageIndex;
    }

    private void SetNodeChecked(TreeNode node, bool checkedState)
    {
        node.Checked = checkedState;
        foreach (TreeNode child in node.Nodes)
        {
            SetNodeChecked(child, checkedState);
        }
    }

    private void UpdateStateIndices(TreeNode node)
    {
        while (node != null)
        {
            UpdateStateImageIndex(node);
            node = node.Parent;
        }
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        TreeViewHitTestInfo hitTestInfo = HitTest(e.Location);
        if (hitTestInfo.Location == TreeViewHitTestLocations.Image)
        {
            TreeNode node = hitTestInfo.Node;
            if (node != null)
            {
                int currentState = GetEffectiveState(node);
                if (currentState == 1)
                {
                    SetNodeChecked(node, false);
                }
                else
                {
                    SetNodeChecked(node, true);
                }
                UpdateStateIndices(node);
            }
        }
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        TreeViewHitTestInfo hitTestInfo = HitTest(e.Location);
        if (hitTestInfo.Location == TreeViewHitTestLocations.Image)
        {
            this.Cursor = Cursors.Hand;
        }
        else
        {
            this.Cursor = Cursors.Default;
        }
    }

    protected override void OnAfterCheck(TreeViewEventArgs e)
    {
        base.OnAfterCheck(e);
        UpdateStateIndices(e.Node);
    }

    private void UpdateStateIndicesRecursive(TreeNode node)
    {
        node.Expand();
        foreach (TreeNode child in node.Nodes)
        {
            UpdateStateIndicesRecursive(child);
        }
        UpdateStateImageIndex(node);
    }

    public void UpdateAllStateIndices()
    {
        foreach (TreeNode node in this.Nodes)
        {
            UpdateStateIndicesRecursive(node);
        }
    }

    protected override void OnBeforeCollapse(TreeViewCancelEventArgs e)
    {
        e.Cancel = true;
    }

    protected override void OnKeyDown(KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
        {
            e.Handled = true;
        }
        base.OnKeyDown(e);
    }

    protected override void OnBeforeSelect(TreeViewCancelEventArgs e)
    {
        e.Cancel = true;
        base.OnBeforeSelect(e);
    }
}

内容的提问来源于stack exchange,提问作者Jamie Head

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 17:11:01