Tutto quello che voglio è aggiornare un testo di ListViewItem senza vedere alcun sfarfallio.
Questo è il mio codice per l'aggiornamento (chiamato più 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 riguardano 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 risolve il problema, ma nel mio caso non l'ha fatto . Credo che questo sia perché sto usando icone su ogni oggetto.
Per terminare questa domanda, ecco una classe di supporto che deve essere chiamata quando il modulo viene caricato per ogni controllo ListView o qualsiasi altro controllo derivato di ListView nel modulo. Grazie a "Brian Gillespie" per aver dato 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);
}
}
La risposta accettata funziona, ma è piuttosto lunga, e derivante dal controllo (come menzionato nelle altre risposte) solo per abilitare il doppio buffering è anche un po 'esagerata. Ma fortunatamente abbiamo una riflessione e possiamo anche chiamare i metodi interni se ci piace (ma sii sicuro di quello che fai!).
Incapsulando questo approccio in un metodo di estensione, otterremo una classe piuttosto breve:
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 facilmente chiamato all'interno del nostro codice:
InitializeComponent();
myListView.DoubleBuffering(true); //after the InitializeComponent();
E tutto lo sfarfallio è sparito.
Ho inciampato su questa domanda ea 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 ListView in CommonControls 6 (XP o successivi) supporta il doppio buffering. Fortunatamente, .NET avvolge i più recenti CommonControls sul sistema. Per abilitare il doppio buffering, inviare il messaggio di Windows appropriato al controllo ListView.
Ecco i dettagli: http://www.codeproject.com/KB/list/listviewxp.aspx
In .NET Winforms 2.0 esiste una proprietà protetta denominata DoubleBuffered.
Tramite l'ereditarietà di ListView, è possibile impostare questa proprietà protetta su true. Ciò abiliterà il doppio buffering senza dover chiamare SendMessage.
L'impostazione della proprietà DoubleBuffered equivale all'impostazione del seguente stile:
listview.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
http://connect.Microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94096
So che questa domanda è abbastanza vecchia, ma poiché questo è uno dei primi risultati di ricerca su Google, volevo condividere la mia correzione.
L'unico modo per rimuovere lo sfarfallio del 100% era combinare la risposta di Oliver (classe di estensione con doppio buffering) e utilizzare i metodi BeignUpdate()
e EndUpdate()
.
Nessuno di quelli da soli potrebbe risolvere lo sfarfallio per me . Concesso, io uso una lista molto complessa, che ho bisogno di inserire nella lista e anche bisogno di aggiornarlo quasi ogni secondo.
questo aiuterà:
class DoubleBufferedListView : System.Windows.Forms.ListView
{
public DoubleBufferedListView()
:base()
{
this.DoubleBuffered = true;
}
}
Se vuoi solo aggiornare il testo, imposta semplicemente il testo di SubItem modificato piuttosto che aggiornare l'intero ListViewItem (non hai detto come stai facendo gli aggiornamenti).
L'override che tu mostri equivale semplicemente a sovrascrivere OnPaintBackground, che sarebbe un modo "più corretto" per farlo, e non sarà di aiuto per un singolo oggetto.
Se hai ancora problemi, avremo bisogno di chiarimenti su ciò che hai effettivamente provato.
Questo è uno sparo al buio, ma potresti provare a doppio buffering del controllo.
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer, true)
Chiamare il metodo BeginUpdate () su ListView prima di impostare uno degli elementi della vista elenco e quindi chiamare solo EndUpdate () dopo aver aggiunto tutti gli elementi.
Ciò fermerà lo sfarfallio.
yourlistview.BeginUpdate ()
// Fai il tuo aggiornamento di aggiungere e rimuovere elementi dalla lista
yourlistview.EndUpdate ()