要将多行文本添加到 ListBox 控件,您需要自己测量和绘制文本。
将ListBox.DrawMode 设置为DrawMode.OwnerDrawVariable,然后覆盖OnMeasureItem 和OnDrawItem。
→ OnMeasureItem 在绘制项目之前调用,以允许定义项目大小,设置 MeasureItemEventArgs e.ItemWidth 和 e.ItemHeight 属性(在尝试测量一项之前,您必须验证 ListBox 是否包含项)。
→ 调用OnDrawItem 时,其DrawItemEventArgs 的e.Bounds 属性将设置为OnMeasureItem 中指定的度量值。
要测量文本,您可以使用TextRenderer 类MeasureText() 方法或Graphics.MeasureString。前者是首选,因为我们将使用 TextRenderer 类来绘制项目的文本:在这种情况下,TextRenderer.DrawText 比 Graphics.DrawString() 更可预测,它呈现文本 自然(就像 ListBox - 或 ListView - 所做的那样)。
TextRenderer 的TextFormatFlags 用于微调渲染行为。我已将 TextFormatFlags.ExpandTabs 添加到标志中,因此您还可以在需要时将选项卡 ("\t") 添加到文本中。请参阅视觉示例。
"\n" 可用于生成换行符。
在示例代码中,我将8 像素添加到项目的测量高度,因为还绘制了行分隔符以更好地定义项目的限制(否则,当项目跨越多行时,可能很难理解其文本的开始和结束位置)。
► 重要提示:最大 Item.Height 为 255 像素。除了这个措施之外,项目的文本可能不会被渲染或部分渲染(但它通常只是消失)。示例代码中对项目高度进行了最小/最大检查。
这就是它的工作原理:
如果你没有,我建议使用类对象来存储你的项目
并描述它们。然后使用List<class> 作为
ListBox.DataSource。这样,您可以更好地定义每个部分
应该渲染。某些部分可能使用粗体或不同的字体
颜色。
using System;
using System.Drawing;
using System.Windows.Forms;
public class ListBoxMultiline : ListBox
{
TextFormatFlags flags = TextFormatFlags.WordBreak |
TextFormatFlags.PreserveGraphicsClipping |
TextFormatFlags.LeftAndRightPadding |
TextFormatFlags.ExpandTabs |
TextFormatFlags.VerticalCenter;
public ListBoxMultiline() { this.DrawMode = DrawMode.OwnerDrawVariable; }
protected override void OnDrawItem(DrawItemEventArgs e)
{
if (Items.Count == 0) return;
if (e.State.HasFlag(DrawItemState.Focus) || e.State.HasFlag(DrawItemState.Selected)) {
using (var selectionBrush = new SolidBrush(Color.Orange)) {
e.Graphics.FillRectangle(selectionBrush, e.Bounds);
}
}
else {
e.DrawBackground();
}
TextRenderer.DrawText(e.Graphics, GetItemText(Items[e.Index]), Font, e.Bounds, ForeColor, flags);
if (e.Index != Items.Count - 1) {
Point lineOffsetStart = new Point(e.Bounds.X, e.Bounds.Bottom - 1);
Point lineOffsetEnd = new Point(e.Bounds.Right, e.Bounds.Bottom - 1);
e.Graphics.DrawLine(Pens.LightGray, lineOffsetStart, lineOffsetEnd);
}
base.OnDrawItem(e);
}
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
if (Items.Count == 0) return;
var size = GetItemSize(e.Graphics, GetItemText(Items[e.Index]));
e.ItemWidth = size.Width;
e.ItemHeight = size.Height;
base.OnMeasureItem(e);
}
private Size GetItemSize(Graphics g, string itemText)
{
var size = TextRenderer.MeasureText(g, itemText, Font, ClientSize, flags);
size.Height = Math.Max(Math.Min(size.Height, 247), Font.Height + 8) + 8;
return size;
}
}