Scintillement dans le contrôle ListView (OwnerDraw, Virtual)

Cette question peut être considérée comme un suivi du scintillement dans une vue de liste avec ownerdraw et virtualmode .

J’ai un contrôle ListView en Virtual mode et je tente d’effectuer un dessin personnalisé. Le rendu d’élément est effectué via la méthode suivante:

 protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs) 

Comme indiqué dans la question mentionnée, le dessin personnalisé introduit le scintillement des événements au survol de la souris. Le débogueur me dit que cela se produit en raison d’un nombre excessif d’événements de dessin personnalisés qui sont déclenchés.


Maintenant – la réponse acceptée à la question référencée nous dit:

Il s’agit d’un bogue dans ListView de .NET et vous ne pouvez pas le contourner en utilisant une double mise en mémoire tampon.

  • Alors, quelle est la fiabilité de cette information? Est-ce vraiment un bug? Ou peut-être que nous essayons simplement de couper une partie des messages et espérons que cela ne modifiera pas le comportement visible?

  • Est-ce vrai que si j’ai ma routine de dessin propriétaire pour ListView en Virtual Mode, je peux supprimer ces événements de Custom Draw et n’effectuer mon dessin que dans WM_PAINT ou, peut-être, est-ce incorrect dans certains cas?

  • Quelles sont les conditions préalables pour que le contrôle System.Windows.Forms puisse faire toute la peinture dans WM_PAINT sans modifier son comportement initial?

J’ai constaté ce problème de scintillement avec le contrôle ListView dans tous les gestionnaires d’événements de rendu personnalisés (DrawItem, DrawSubItem). J’ai essayé BeginUpdate () / EndUpdate () et la double mise en mémoire tampon sans succès. Je pense que .NET déclenche WM_PAINT supplémentaire dans toutes les colonnes à droite de la colonne dessinée .

Cependant, j’ai trouvé cette solution de contournement à une seule colonne de rendu personnalisée, ListView. Cela fonctionne très bien!

  1. Dans l’éditeur de colonnes, définissez la colonne dessinée personnalisée comme dernière colonne.
  2. Changer le “DisplayIndex” de la position que vous voulez

Cela devrait résoudre le scintillement du passage de la souris ou du rendu d’exécution.

Au moins pour la double mise en mémoire tampon pour OnDrawItem, il est incorrect qu’il existe un bogue, mais il est un peu stupide: vous pouvez définir un atsortingbut protégé, mais vous devez remplacer le contrôle ListView. J’ai créé ce genre de cours:

 public class MyListView : ListView { public MyListView() : base() { DoubleBuffered = true; } } 

Et puis dans mon fichier MyForm.Designer.cs, je modifie l’instanciation de ListView avec la ligne suivante:

 private ListView myListView; this.myListView = new MyListView(); 

Et OnDrawItem fonctionnera à merveille!

Comme cette réponse ici , mais pas sûr mais,

Je pense que ListView.BeginUpdate() et ListView.EndUpdate() vont résoudre le problème.

Fil de MSDN à propos de cela

Peut-être de cette façon:

 protected override void OnDrawItem(DrawListViewItemEventArgs eventArgs) { ListView.BeginUpdate(); //Do Works Here ListView.EndUpdate(); } 

Mettre à jour

Une autre alternative peut utiliser un nouveau thread dans BackgroundWorker pour mettre à jour la liste … J’ai implémenté cela avec BeginUpdate() / EndUpDate() dans mon application et je l’ai trouvé relativement plus rapidement que seulement BeginUpdate() / EndUpDate() ..

Mettre à jour

J’ai trouvé une autre solution de travail à SO , un cours Helper fourni par Brian Gillespie :

 public enum ListViewExtendedStyles { ///  /// LVS_EX_GRIDLINES ///  GridLines = 0x00000001, ///  /// LVS_EX_SUBITEMIMAGES ///  SubItemImages = 0x00000002, ///  /// LVS_EX_CHECKBOXES ///  CheckBoxes = 0x00000004, ///  /// LVS_EX_TRACKSELECT ///  TrackSelect = 0x00000008, ///  /// LVS_EX_HEADERDRAGDROP ///  HeaderDragDrop = 0x00000010, ///  /// LVS_EX_FULLROWSELECT ///  FullRowSelect = 0x00000020, ///  /// LVS_EX_ONECLICKACTIVATE ///  OneClickActivate = 0x00000040, ///  /// LVS_EX_TWOCLICKACTIVATE ///  TwoClickActivate = 0x00000080, ///  /// LVS_EX_FLATSB ///  FlatsB = 0x00000100, ///  /// LVS_EX_REGIONAL ///  Regional = 0x00000200, ///  /// LVS_EX_INFOTIP ///  InfoTip = 0x00000400, ///  /// LVS_EX_UNDERLINEHOT ///  UnderlineHot = 0x00000800, ///  /// LVS_EX_UNDERLINECOLD ///  UnderlineCold = 0x00001000, ///  /// LVS_EX_MULTIWORKAREAS ///  MultilWorkAreas = 0x00002000, ///  /// LVS_EX_LABELTIP ///  LabelTip = 0x00004000, ///  /// LVS_EX_BORDERSELECT ///  BorderSelect = 0x00008000, ///  /// LVS_EX_DOUBLEBUFFER ///  DoubleBuffer = 0x00010000, ///  /// LVS_EX_HIDELABELS ///  HideLabels = 0x00020000, ///  /// LVS_EX_SINGLEROW ///  SingleRow = 0x00040000, ///  /// LVS_EX_SNAPTOGRID ///  SnapToGrid = 0x00080000, ///  /// LVS_EX_SIMPLESELECT ///  SimpleSelect = 0x00100000 } public enum ListViewMessages { First = 0x1000, SetExtendedStyle = (First + 54), GetExtendedStyle = (First + 55), } ///  /// Contains helper methods to change extended styles on ListView, including enabling double buffering. /// Based on Giovanni Montrone's article on  ///  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); } }