Переопределение DrawItem для ListBox - невыбранные элементы не перерисовываются

StackOverflow https://stackoverflow.com/questions/3274861

Вопрос

Это настольное приложение на 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");

Кроме того, элемент, который нарисован правильно (выбранный), мерцает при изменении размера формы.Ничего особенного, но если кто-нибудь знает почему....спасибо

Это было полезно?

Решение

Поместите следующий код в событие изменения размера:

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);
        }
    }
}

Замените "Whatever" пространством имен, используемым вашим проектом, или сделайте его чем-то более полезным.После компиляции вы должны иметь возможность добавить DBListBox в конструкторе форм.

Другие советы

Я повторяю проблему.В коде есть несколько ошибок, название шрифта "Arial", вам не следует настраивать rect.Ширина, вы забыли вызвать Dispose() для шрифтов, кистей и областей.Но они не объясняют такого поведения.Что-то не так с областью обрезки, которая препятствует правильному обновлению текста.Я не вижу, где это происходит, состояние графического объекта в порядке.

Графика.DrawString() - очень проблемный метод, вам действительно следует избегать его.Все элементы управления Windows Forms, включая ListBox, используют TextRenderer.DrawText().Это решает проблему, когда я им пользуюсь.Я знаю, что измерение сложнее, вы могли бы обойти это, отобразив IP-адрес с фиксированным смещением.Тоже выглядит лучше, так они выстроятся в колонну.

Он мерцает, потому что вы используете e.drawBackground().Это стирает существующий текст, и вы рисуете текст прямо на нем.Я не думаю, что двойная буферизация исправит это, вам пришлось бы рисовать весь элемент целиком, чтобы вам не приходилось рисовать фон.Сложно, если вы не можете получить точный размер текста крупным шрифтом, обходной путь заключается в том, чтобы сначала нарисовать растровое изображение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top