自动调整大小的C# ListBox






3.67/5 (9投票s)
2002年7月16日
2分钟阅读

236080

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



问题是什么?
我需要编写一个小工具来根据文件格式规范验证输入文件。为了给应用程序增加一些视觉效果,我希望包含一个小状态窗口,其中显示所有相关的解析消息(错误、警告等)以及一些描述性文本。
所以第一次尝试是从标准的 ListBox
类继承并实现自定义绘制代码,使用一个小图标、标题和消息文本。为了支持不同的文本大小,我订阅了 MeasureItem
事件,并为每个项目单独计算项目高度。这工作得很好,直到我第一次调整控件大小:不再触发 MeasureItem
事件!
快速查看文档显示了以下句子:“当拥有者绘制的 ListBox 被创建时发生”。由于我是在运行时将解析消息添加到 ListBox 中,因此持续重新创建控件不是一个选项(而且效率低下)。所以这是一个死胡同。
解决方案
在尝试了一些可能的解决方法但没有成功之后,我得出结论,这需要一种更根本的方法:我必须编写一个自己的 ListBox,它从一开始就表现得像标准的 ListBox 那样。任务比我最初预期的要容易。
该解决方案基本上由两个类组成:ResizableListBox
和 MessageListBox
。前者是标准 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
...
}