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

设置ListBox的DrawMode为OwnerDrawFixed时水平滚动条不显示问题咨询

嘿,我帮你揪出了水平滚动条不显示的问题!

你现在的核心问题出在MeasureItem事件的逻辑上,还有个容易忽略的小细节,咱们拆解来看:

问题到底出在哪?

  1. HorizontalExtent被反复覆盖成单一项的宽度:你每次在MeasureItem里把滚动范围设为当前项的宽度,如果后面遇到更短的项,这个值就会被缩小——滚动条只有当内容总宽度超过控件自身宽度时才会显示,所以最长项的宽度没被保留的话,滚动条自然不会出来。
  2. (可选但重要)你用Graphics.DrawString绘制文本,和TextRenderer.MeasureText的测量逻辑不一致,可能导致实际绘制的宽度和你测量的有偏差,就算滚动条出来了,文本显示也可能不对。

怎么修复?

第一步:修正MeasureItem,记录最大宽度

咱们加个全局变量存所有项里最宽的那个值,只在遇到更宽的项时才更新HorizontalExtent,同时别忘了开启水平滚动条属性:

private int _maxItemWidth = 0; // 用来存所有项里最宽的宽度

// 初始化时务必开启水平滚动条!
articlesLB.DrawMode = DrawMode.OwnerDrawFixed;
articlesLB.HorizontalScrollbar = true;
articlesLB.MeasureItem += articlesLB_MeasureItem;
articlesLB.DrawItem += articlesLB_SetColor;

private void articlesLB_MeasureItem(object sender, MeasureItemEventArgs e)
{
    string itemText = articlesLB.Items[e.Index].ToString();
    int currentWidth = TextRenderer.MeasureText(itemText, articlesLB.Font).Width;
    
    // 只有当前项比之前的最大值宽,才更新滚动范围
    if (currentWidth > _maxItemWidth)
    {
        _maxItemWidth = currentWidth;
        articlesLB.HorizontalExtent = _maxItemWidth;
    }
}

第二步:优化绘制逻辑,保证测量和绘制一致

把Graphics.DrawString换成TextRenderer.DrawText,因为它和你用来测量宽度的TextRenderer.MeasureText是一套逻辑,不会出现宽度不匹配的问题:

private void articlesLB_SetColor(object sender, DrawItemEventArgs e)
{
    if (e.Index < 0) return;
    
    ListBox listBox = (ListBox)sender;
    string itemText = listBox.Items[e.Index].ToString();
    
    // 处理选中状态的背景色
    Color bgColor = (e.State & DrawItemState.Selected) == DrawItemState.Selected 
        ? Color.Yellow 
        : listBox.BackColor;
    
    // 先绘制背景
    using (SolidBrush bgBrush = new SolidBrush(bgColor))
    {
        e.Graphics.FillRectangle(bgBrush, e.Bounds);
    }
    
    // 选择文本颜色
    Brush textBrush = Brushes.Black;
    if (EditAOSideRB.Checked || EditAPinSideRB.Checked)
    {
        textBrush = itemText.Contains("* ") ? Brushes.DarkGreen : Brushes.Red;
    }
    
    // 用TextRenderer绘制,保证和测量的宽度完全匹配
    TextRenderer.DrawText(e.Graphics, itemText, listBox.Font, e.Bounds, 
        textBrush.Color, bgColor, TextFormatFlags.Left);
    
    // 绘制焦点矩形
    if ((e.State & DrawItemState.Focus) == DrawItemState.Focus)
    {
        e.DrawFocusRectangle();
    }
}

第三步:数据源更新时重置最大值

如果之后你要添加或删除ListBox的项,记得把_maxItemWidth重置为0,然后刷新控件,不然新的长项可能不会触发滚动条更新:

// 示例:更新ListBox数据源的方法
private void RefreshListBoxItems(List<string> newItems)
{
    _maxItemWidth = 0;
    articlesLB.Items.Clear();
    articlesLB.Items.AddRange(newItems.ToArray());
    articlesLB.Refresh(); // 触发重新测量所有项的宽度
}

这样改完,水平滚动条就会根据最长项的宽度自动显示,文本超出边界时也能正常滚动啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 12:38:13