Come evitare lo sfarfallio nella ListView quando l'aggiornamento di un singolo ListViewItem del testo?

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

  •  01-07-2019
  •  | 
  •  

Domanda

Tutto quello che voglio è quello di aggiornare un ListViewItem testo senza vedere alcun sfarfallio.

Questo è il mio codice per l'aggiornamento (chiamato diverse volte):

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

Ho visto alcune soluzioni che coinvolgono l'override del componente WndProc():

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

Dicono che si risolve il problema, ma nel mio caso non.Credo che questo è perché sto usando le icone su ogni articolo.

È stato utile?

Soluzione 2

Per porre fine a questa domanda, qui è una classe di supporto che dovrebbe essere chiamato quando il modulo è in fase di caricamento per ogni ListView o qualsiasi altro ListView derivato di controllo nel modulo.Grazie a "Brian Gillespie" per dare la soluzione.

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

Altri suggerimenti

Accettato di rispondere opere, ma è abbastanza lungo, e derivanti dal controllo (come già detto in altre risposte) solo per abilitare il double buffering è anche un po ' esagerato.Ma fortunatamente abbiamo riflessione e metodi interni se ci piace (ma essere sicuri di cosa fare!!).

Essere incapsulamento di questo approccio in un metodo di estensione, avremo una abbastanza breve di classe:

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

Che può essere tranquillamente definito all'interno del codice:

InitializeComponent();

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

E tutti lo sfarfallio è andato.

Aggiornamento

Mi sono imbattuto in questa domanda e a causa di questo fatto, il metodo di estensione dovrebbe (forse) essere meglio:

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

Il controllo ListView in CommonControls 6 (XP o più recente) supporta il doppio buffer.Per fortuna, .NET avvolge il più recente CommonControls sul sistema.Per abilitare il double buffering, inviare un appropriato messaggio di Windows per il controllo ListView.

Ecco i dettagli:http://www.codeproject.com/KB/list/listviewxp.aspx

In .NET Winforms 2.0 esiste una proprietà protetta denominata DoubleBuffered.

Ereditando dalla ListView, allora si può impostare questa proprietà su true.Questo consentirà di abilitare il double buffering, senza bisogno di chiamare SendMessage.

Impostazione del DoubleBuffered proprietà è la stessa impostazione di stile riportato di seguito:

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

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

So che questa domanda è abbastanza vecchio, ma perché questo è uno dei primi risultati di ricerca su Google ho voluto condividere la mia correzione.

L'unico modo per rimuovere lo sfarfallio 100%, unire la risposta da Oliver (classe di estensione con il doppio buffering) e utilizzando il BeignUpdate() e EndUpdate() i metodi.

Nessuno di coloro che potrebbero risolvere tremolante per me.Concesso, io uso molto complesso lista, che ho bisogno di inserire in lista e anche necessario aggiornare quasi ogni sec.

questo vi aiuterà a:

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

Soluzione semplice è questo:

yourlistview.BeginUpdate()

//Esegue l'aggiornamento di aggiunta e rimozione di elemento dall'elenco

yourlistview.EndUpdate()

Se solo si desidera aggiornare il testo, è sufficiente impostare la cambiata Sottovoce di testo direttamente, piuttosto che aggiornare l'intera ListViewItem (non hai detto come stai facendo gli aggiornamenti).

La sostituzione che si mostra è equivalente semplicemente sovrascrivere OnPaintBackground, che sarebbe un "più corretto" gestito modo per fare questo compito, e non sta andando per aiutare per un singolo elemento.

Se hai ancora problemi, abbiamo bisogno di un chiarimento su quello che hai provato.

Questo è uno sparo nel buio, ma si potrebbe provare il double buffering controllo.

SetStyle(
  ControlStyles.AllPaintingInWmPaint |
  ControlStyles.UserPaint |
  ControlStyles.DoubleBuffer, true)

Chiamare il BeginUpdate() metodo ListView prima di impostare qualsiasi dell'elenco di visualizzare elementi e quindi chiamare solo EndUpdate() dopo che tutti gli elementi sono stati aggiunti.

Che possano fermare il tremolio.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top