Überschreiben von DrawItem für ListBox – nicht ausgewählte Elemente werden nicht neu gezeichnet

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

Frage

Dies ist eine C#-Desktopanwendung.Der DrawStyle Eigentum von mir ListBox ist eingestellt auf OwnerDrawFixed.

Das Problem: Ich überschreibe DrawItem, um Text in verschiedenen Schriftarten zu zeichnen, und es funktioniert.Aber wenn ich zur Laufzeit anfange, die Größe des Formulars zu ändern, wird das ausgewählte Element korrekt gezeichnet, der Rest wird jedoch nicht neu gezeichnet, was dazu führt, dass der Text für nicht ausgewählte Elemente beschädigt aussieht.

Hier ist mein Code:

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

Außerdem flackert das korrekt gezeichnete Element (das ausgewählte) bei der Größenänderung des Formulars.Kein Problem, aber wenn jemand weiß warum ...tnx

War es hilfreich?

Lösung

Fügen Sie den folgenden Code in das Resize-Ereignis ein:

private void listDevices_Resize(object sender, EventArgs e) {
    listDevices.Invalidate();
}

Dies sollte dazu führen, dass alles neu gezeichnet wird.

Um das Flackern zu stoppen, ist eine doppelte Pufferung erforderlich.

Erstellen Sie dazu eine neue Klasse, die von ListBox abgeleitet ist, und fügen Sie Folgendes in den Konstruktor ein:

this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

Oder fügen Sie dies einfach in eine Codedatei ein:

using System.Windows.Forms;

namespace Whatever {
    public class DBListBox : ListBox {
        public DBListBox(): base() {
            this.DoubleBuffered = true;
            // OR
            // this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        }
    }
}

Ersetzen Sie „Whatever“ durch den Namespace, den Ihr Projekt verwendet, oder machen Sie ihn zu einem nützlicheren Namespace.Nach dem Kompilieren sollten Sie in der Lage sein, im Formulardesigner eine DBListBox hinzuzufügen.

Andere Tipps

Ich behaupte das Problem.Es gibt mehrere Fehler im Code, der Schriftartname ist „Arial“, Sie sollten rect.Width nicht anpassen, Sie vergessen, Dispose() für die Schriftarten, Pinsel und Regionen aufzurufen.Aber sie erklären das Verhalten nicht.Es liegt ein Fehler im Beschneidungsbereich vor, der verhindert, dass der Text ordnungsgemäß aktualisiert wird.Ich sehe nicht, wo das auftritt, der Status des Grafikobjekts ist in Ordnung.

Graphics.DrawString() ist eine sehr problematische Methode, Sie sollten sie unbedingt vermeiden.Alle Windows Forms-Steuerelemente, einschließlich ListBox, verwenden TextRenderer.DrawText().Das löst das Problem, wenn ich es verwende.Ich weiß, dass das Messen schwieriger ist. Sie könnten das umgehen, indem Sie die IP-Adresse mit einem festen Offset anzeigen.Sieht auch besser aus, da sie so in einer Spalte angeordnet sind.

Es flackert, weil Sie e.DrawBackground() verwenden.Dadurch wird der vorhandene Text gelöscht, Sie zeichnen den Text direkt darauf zurück.Ich glaube nicht, dass die doppelte Pufferung das Problem beheben wird. Sie müssten das gesamte Element zeichnen, damit Sie nicht den Hintergrund zeichnen müssen.Wenn Sie mit der großen Schriftart nicht die exakte Größe des Textes ermitteln können, kann es schwierig sein, zuerst in eine Bitmap zu zeichnen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top