Чтобы добавить многострочный текст в элемент управления ListBox, необходимо измерить и нарисовать текст самостоятельно.
Установите ListBox.DrawMode на DrawMode.OwnerDrawVariable , затем переопределите OnMeasureItem и OnDrawItem .
→ OnMeasureItem
вызывается до рисования элемента, чтобы дать возможность определить размер элемента, устанавливая MeasureItemEventArgs e.ItemWidth
и e.ItemHeight
свойств (вы должны убедиться, что ListBox содержит элементы, прежде чем пытаться измерить один).
→ Когда вызывается OnDrawItem
, свойство e.Bounds
его DrawItemEventArgs будет установлено в меру, указанную в OnMeasureItem
.
Для измерения текста вы можете использовать метод TextRenderer class 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.GlyphOverhangPadding |
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;
}
}