Переопределение DrawItem для ListBox - невыбранные элементы не перерисовываются
Это настольное приложение на C#. DrawStyle
собственность моего ListBox
установлен в OwnerDrawFixed
,
Проблема: я перезаписываю DrawItem, чтобы рисовать текст разными шрифтами, и это работает. Но когда я начинаю изменять размер формы во время выполнения, выбранный элемент рисуется правильно, но остальные не перерисовываются, что приводит к искажению текста для невыбранных элементов.
Вот мой код:
private void listDevices_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
string textDevice = ((ListBox)sender).Items[e.Index].ToString();
e.Graphics.DrawString(textDevice,
new Font("Ariel", 15, FontStyle.Bold), new SolidBrush(Color.Black),
e.Bounds, StringFormat.GenericDefault);
// Figure out where to draw IP
StringFormat copy = new StringFormat(
StringFormatFlags.NoWrap |
StringFormatFlags.MeasureTrailingSpaces
);
copy.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0, textDevice.Length)});
Region[] regions = e.Graphics.MeasureCharacterRanges(
textDevice, new Font("Ariel", 15, FontStyle.Bold), e.Bounds, copy);
int width = (int)(regions[0].GetBounds(e.Graphics).Width);
Rectangle rect = e.Bounds;
rect.X += width;
rect.Width -= width;
// draw IP
e.Graphics.DrawString(" 255.255.255.255",
new Font("Courier New", 10), new SolidBrush(Color.DarkBlue),
rect, copy);
e.DrawFocusRectangle();
}
listDevices.Items.Add("Device001");
listDevices.Items.Add("Device002");
Кроме того, элемент, который рисуется правильно (выбранный), мигает при изменении размера формы. Не важно, но если кто-нибудь знает, почему.... TNX
2 ответа
Поместите следующий код в событие Resize:
private void listDevices_Resize(object sender, EventArgs e) {
listDevices.Invalidate();
}
Это должно привести к перерисовке всего.
Чтобы остановить мерцание, вам нужна двойная буферизация.
Для этого создайте новый класс, производный от ListBox, и поместите в конструктор следующее:
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
Или просто вставьте это в файл кода:
using System.Windows.Forms;
namespace Whatever {
public class DBListBox : ListBox {
public DBListBox(): base() {
this.DoubleBuffered = true;
// OR
// this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
}
}
Замените "Что угодно" пространством имен, используемым вашим проектом, или сделайте его более полезным. После компиляции вы сможете добавить DBListBox в конструктор форм.
Я повторяю проблему. В коде есть несколько ошибок, имя шрифта "Arial", вы не должны корректировать rect.Width, вы забыли вызвать Dispose() для шрифтов, кистей и областей. Но они не объясняют поведение. Что-то не так с областью отсечения, которая препятствует правильному обновлению текста. Я не вижу, где это происходит, состояние объекта Graphics в порядке.
Graphics.DrawString () - очень проблемный метод, вам следует избегать его. Все элементы управления Windows Forms, включая ListBox, используют TextRenderer.DrawText(). Это решает проблему, когда я его использую. Я знаю, что измерение труднее, вы можете обойти это, отображая IP-адрес с фиксированным смещением. Выглядит лучше, они выстроятся в столбец таким образом.
Мерцает, потому что вы используете e.DrawBackground(). Это стирает существующий текст, вы рисуете текст обратно на него. Я не думаю, что двойная буферизация это исправит, вам нужно нарисовать весь элемент, чтобы не рисовать фон. Сложно, если вы не можете получить точный размер текста крупным шрифтом, обходной путь - сначала нарисовать растровое изображение.