65.9K
CodeProject 正在变化。 阅读更多。
Home

自动调整大小的C# ListBox

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.67/5 (9投票s)

2002年7月16日

2分钟阅读

viewsIcon

236080

downloadIcon

3830

一个可以自动调整其项大小的自定义ListBox。

Before resize After resize After another resize

问题是什么?

我需要编写一个小工具来根据文件格式规范验证输入文件。为了给应用程序增加一些视觉效果,我希望包含一个小状态窗口,其中显示所有相关的解析消息(错误、警告等)以及一些描述性文本。

所以第一次尝试是从标准的 ListBox 类继承并实现自定义绘制代码,使用一个小图标、标题和消息文本。为了支持不同的文本大小,我订阅了 MeasureItem 事件,并为每个项目单独计算项目高度。这工作得很好,直到我第一次调整控件大小:不再触发 MeasureItem 事件!

快速查看文档显示了以下句子:“当拥有者绘制的 ListBox 被创建时发生”。由于我是在运行时将解析消息添加到 ListBox 中,因此持续重新创建控件不是一个选项(而且效率低下)。所以这是一个死胡同。

解决方案

在尝试了一些可能的解决方法但没有成功之后,我得出结论,这需要一种更根本的方法:我必须编写一个自己的 ListBox,它从一开始就表现得像标准的 ListBox 那样。任务比我最初预期的要容易。

该解决方案基本上由两个类组成:ResizableListBoxMessageListBox。前者是标准 ListBox 类的替代品。它试图尽可能地模拟真实的 ListBox,包括事件、属性和方法。虽然我必须承认它不是 100% 完整的(缺少数据绑定),但在大多数情况下应该可以解决问题。单独使用时,它不会提供任何比原始 ListBox 更多的优势。唯一的区别是,它会在每次控件重绘时触发 MeasureItem 事件。后者实现了实际的自定义 ListBox 和精美的绘制。

如何使用

首先将 ResizableListBox 添加到您的项目中。然后创建派生类并订阅 MeasureItem 事件

public class MessageListBox : ResizableListBox 
{
    public MessageListBox()
    {    
        InitializeComponent();                    
        this.MeasureItem += new MeasureItemEventHandler(
	    this.MeasureItemHandler);
        
        //more ctor code here
        ...
    }
        
    ...
}

添加事件处理程序并设置 MeasureItemEventArgs.ItemHeight 属性

private void MeasureItemHandler(
    object sender, MeasureItemEventArgs e)
{

    int MainTextHeight;            
    ParseMessageEventArgs item;
    item =  (ParseMessageEventArgs) Items[e.Index];
    int LinesFilled, CharsFitted;
            
    // as we do not use the same algorithm to calculate 
    // the size of the text (for performance reasons)
    // we need to add some safety margin ( the 0.9 factor ) 
    // to ensure that always all text is displayed
    int width = (int)((this.Width - m_MainTextOffset) * 0.9);
    int height = 200;
    Size sz = new Size(width , height);    

    e.Graphics.MeasureString(item.MessageText, this.Font, sz,
        StringFormat.GenericDefault, out CharsFitted, 
        out LinesFilled);
            
    MainTextHeight = LinesFilled * this.Font.Height;

    e.ItemHeight = IconList.ImageSize.Height + MainTextHeight + 4;
}

实现您自己的绘制代码也是有意义的

protected override void OnDrawItem( DrawItemEventArgs e)
{
    //custom drawing goes here
    ...
}
© . All rights reserved.