it-swarm-eu.dev

Wie kann das Flimmern in ListView beim Aktualisieren eines einzelnen ListViewItem-Texts verhindert werden?

Alles, was ich möchte, ist das Aktualisieren eines ListViewItem-Textes, ohne dass ein Flackern auftritt.

Dies ist mein Code zum Aktualisieren (mehrmals aufgerufen):

listView.BeginUpdate();
listViewItem.SubItems[0].Text = state.ToString();    // update the state
listViewItem.SubItems[1].Text = progress.ToString(); // update the progress
listView.EndUpdate();

Ich habe einige Lösungen gesehen, bei denen die WndProc(): der Komponente überschrieben wird.

protected override void WndProc(ref Message m)
{
    if (m.Msg == (int)WM.WM_ERASEBKGND)
    {
        m.Msg = (int)IntPtr.Zero;
    }
    base.WndProc(ref m);
}

Sie sagen, es löst das Problem, aber in meinem Fall nicht . Ich glaube, das liegt daran, dass ich für jedes Element Icons benutze.

46
Jonas

Um diese Frage zu beenden, ist hier eine Hilfsklasse, die aufgerufen werden sollte, wenn das Formular für jede ListView oder jedes abgeleitete Steuerelement einer ListView in Ihrem Formular geladen wird. Danke an "Brian Gillespie" für die Lösung.

public enum ListViewExtendedStyles
{
    /// <summary>
    /// LVS_EX_GRIDLINES
    /// </summary>
    GridLines = 0x00000001,
    /// <summary>
    /// LVS_EX_SUBITEMIMAGES
    /// </summary>
    SubItemImages = 0x00000002,
    /// <summary>
    /// LVS_EX_CHECKBOXES
    /// </summary>
    CheckBoxes = 0x00000004,
    /// <summary>
    /// LVS_EX_TRACKSELECT
    /// </summary>
    TrackSelect = 0x00000008,
    /// <summary>
    /// LVS_EX_HEADERDRAGDROP
    /// </summary>
    HeaderDragDrop = 0x00000010,
    /// <summary>
    /// LVS_EX_FULLROWSELECT
    /// </summary>
    FullRowSelect = 0x00000020,
    /// <summary>
    /// LVS_EX_ONECLICKACTIVATE
    /// </summary>
    OneClickActivate = 0x00000040,
    /// <summary>
    /// LVS_EX_TWOCLICKACTIVATE
    /// </summary>
    TwoClickActivate = 0x00000080,
    /// <summary>
    /// LVS_EX_FLATSB
    /// </summary>
    FlatsB = 0x00000100,
    /// <summary>
    /// LVS_EX_REGIONAL
    /// </summary>
    Regional = 0x00000200,
    /// <summary>
    /// LVS_EX_INFOTIP
    /// </summary>
    InfoTip = 0x00000400,
    /// <summary>
    /// LVS_EX_UNDERLINEHOT
    /// </summary>
    UnderlineHot = 0x00000800,
    /// <summary>
    /// LVS_EX_UNDERLINECOLD
    /// </summary>
    UnderlineCold = 0x00001000,
    /// <summary>
    /// LVS_EX_MULTIWORKAREAS
    /// </summary>
    MultilWorkAreas = 0x00002000,
    /// <summary>
    /// LVS_EX_LABELTIP
    /// </summary>
    LabelTip = 0x00004000,
    /// <summary>
    /// LVS_EX_BORDERSELECT
    /// </summary>
    BorderSelect = 0x00008000,
    /// <summary>
    /// LVS_EX_DOUBLEBUFFER
    /// </summary>
    DoubleBuffer = 0x00010000,
    /// <summary>
    /// LVS_EX_HIDELABELS
    /// </summary>
    HideLabels = 0x00020000,
    /// <summary>
    /// LVS_EX_SINGLEROW
    /// </summary>
    SingleRow = 0x00040000,
    /// <summary>
    /// LVS_EX_SNAPTOGRID
    /// </summary>
    SnapToGrid = 0x00080000,
    /// <summary>
    /// LVS_EX_SIMPLESELECT
    /// </summary>
    SimpleSelect = 0x00100000
}

public enum ListViewMessages
{
    First = 0x1000,
    SetExtendedStyle = (First + 54),
    GetExtendedStyle = (First + 55),
}

/// <summary>
/// Contains helper methods to change extended styles on ListView, including enabling double buffering.
/// Based on Giovanni Montrone's article on <see cref="http://www.codeproject.com/KB/list/listviewxp.aspx"/>
/// </summary>
public class ListViewHelper
{
    private ListViewHelper()
    {
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr handle, int messg, int wparam, int lparam);

    public static void SetExtendedStyle(Control control, ListViewExtendedStyles exStyle)
    {
        ListViewExtendedStyles styles;
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        styles |= exStyle;
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }

    public static void EnableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // enable double buffer and border select
        styles |= ListViewExtendedStyles.DoubleBuffer | ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
    public static void DisableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // disable double buffer and border select
        styles -= styles & ListViewExtendedStyles.DoubleBuffer;
        styles -= styles & ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
}
51
Jonas

Die akzeptierte Antwort funktioniert, ist jedoch recht langwierig, und aus der Kontrolle (wie in den anderen Antworten erwähnt) nur das Doppelpuffern zu aktivieren, ist ebenfalls etwas übertrieben. Aber zum Glück haben wir Nachdenken und können auch interne Methoden aufrufen, wenn wir möchten (aber seien Sie sicher, was Sie tun!).

Wenn Sie diesen Ansatz in eine Erweiterungsmethode kapseln, erhalten Sie eine recht kurze Klasse:

public static class ControlExtensions
{
    public static void DoubleBuffering(this Control control, bool enable)
    {
        var method = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);
        method.Invoke(control, new object[] { ControlStyles.OptimizedDoubleBuffer, enable });
    }
}

Welches kann leicht in unserem Code aufgerufen werden:

InitializeComponent();

myListView.DoubleBuffering(true); //after the InitializeComponent();

Und alles Flackern ist weg.

Aktualisieren

Ich stolperte über diese Frage und aufgrund dieser Tatsache sollte die Erweiterungsmethode (vielleicht) besser sein:

public static void DoubleBuffered(this Control control, bool enable)
{
    var doubleBufferPropertyInfo = control.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
    doubleBufferPropertyInfo.SetValue(control, enable, null);
}
58
Oliver

Die ListView in CommonControls 6 (XP oder neuer) unterstützt die doppelte Pufferung. Glücklicherweise umschließt .NET die neuesten CommonControls auf dem System. Um die doppelte Pufferung zu aktivieren, senden Sie die entsprechende Windows-Nachricht an das ListView-Steuerelement.

Hier sind die Details: http://www.codeproject.com/KB/list/listviewxp.aspx

11
Brian Gillespie

In .NET Winforms 2.0 gibt es eine geschützte Eigenschaft namens DoubleBuffered.

Durch das Erben von ListView kann diese geschützte Eigenschaft auf true gesetzt werden. Dies ermöglicht die doppelte Pufferung, ohne dass SendMessage aufgerufen werden muss.

Das Festlegen der DoubleBuffered-Eigenschaft entspricht dem Festlegen des folgenden Stils:

listview.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

http://connect.Microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94096

10
Rolf Kristensen

Ich weiß, dass diese Frage ziemlich alt ist, aber da dies eines der ersten Suchergebnisse bei Google ist, wollte ich meinen Fix teilen.

Die einzige Möglichkeit, flackernde 100% zu entfernen, bestand darin, die Antwort von Oliver (Erweiterungsklasse mit doppelter Pufferung) zu kombinieren und die Methoden BeignUpdate() und EndUpdate() zu verwenden.

Keiner von ihnen konnte das Flimmern für mich beheben. Ich gebe eine sehr komplexe Liste, die ich in die Liste schieben muss und sie fast jede Sekunde aktualisieren muss.

2
T4cC0re

das wird helfen:

class DoubleBufferedListView : System.Windows.Forms.ListView
{
    public DoubleBufferedListView()
        :base()
    {
        this.DoubleBuffered = true;
    }
}
1
Bjoern

Wenn Sie nur den Text aktualisieren möchten, setzen Sie einfach den geänderten SubItem-Text direkt, anstatt das gesamte ListViewItem zu aktualisieren (Sie haben nicht gesagt, wie Sie Ihre Aktualisierungen durchführen).

Die Überschreibung, die Sie anzeigen, ist gleichbedeutend mit der einfachen Überschreibung von OnPaintBackground. Dies wäre ein "korrekter" verwalteter Weg, um diese Aufgabe auszuführen, und es wird nicht für ein einzelnes Element hilfreich sein.

Wenn Sie immer noch Probleme haben, müssen wir klären, was Sie tatsächlich versucht haben.

0
ctacke

Dies ist eine Einstellung im Dunkeln, aber Sie können versuchen, das Steuerelement doppelt zu puffern.

SetStyle(
  ControlStyles.AllPaintingInWmPaint |
  ControlStyles.UserPaint |
  ControlStyles.DoubleBuffer, true)
0
Ed S.

Rufen Sie die BeginUpdate () - Methode in der ListView auf, bevor Sie eines der Listenansichtselemente festlegen, und rufen Sie EndUpdate () erst auf, nachdem alle Elemente hinzugefügt wurden.

Das wird das Flimmern stoppen.

0
Mike

Einfache Lösung ist dies:

yourlistview.BeginUpdate ()

// Aktualisieren Sie das Hinzufügen und Entfernen von Elementen aus der Liste

yourlistview.EndUpdate ()

0
jaiveeru