2010-08-01 14 views
3

J'utilise ListView dans VirtualMode et Details View avec de petites icônes.WinForms ListView dessine HELL SLOW dans Windows 7 par rapport à XP

Cette liste contient 100 000 articles. Le problème est que le dessin de cette liste est beaucoup plus lent dans Windows 7 par rapport à XP.

Vous pouvez remplir le dessin lent tout en faisant défiler le ListView ou en sélectionnant plusieurs éléments.

En outre, j'ai remarqué que le dessin devient plus lent avec chaque colonne ajoutée.

Le gestionnaire d'événements RetrieveVirtualItem ne fait rien pour renvoyer les valeurs littérales, donc ce n'est pas le goulot d'étranglement.

Des idées?

MISE À JOUR: Le code source pour reproduire:

FlickerFreeListView.cs:

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 
using System.ComponentModel; 
using System.Drawing; 
using System.Reflection; 
using System.Diagnostics; 

namespace ListViewTest 
{ 
    public class FlickerFreeListView : ListView 
    { 
     public FlickerFreeListView() 
     { 
      base.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); 
     } 
    } 
} 

form1.cs:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Diagnostics; 

namespace ListViewTest 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 

      _item = new ListViewItem(new string[6]); 
     } 

     private ListViewItem _item; 

     private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) 
     { 
      string itemIndexStr = e.ItemIndex.ToString(); 
      _item.Text = itemIndexStr; 
      _item.SubItems[1].Text = "blablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablabla"; 
      _item.SubItems[2].Text = itemIndexStr; 
      _item.SubItems[3].Text = itemIndexStr; 
      _item.SubItems[4].Text = itemIndexStr; 
      _item.SubItems[5].Text = itemIndexStr; 
      e.Item = _item; 
     } 
    } 
} 

Form1.Designer.cs:

namespace ListViewTest 
{ 
    partial class Form1 
    { 
     /// <summary> 
     /// Required designer variable. 
     /// </summary> 
     private System.ComponentModel.IContainer components = null; 

     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Form Designer generated code 

     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.listView1 = new ListViewTest.FlickerFreeListView(); 
      this.columnHeader1 = new System.Windows.Forms.ColumnHeader(); 
      this.columnHeader2 = new System.Windows.Forms.ColumnHeader(); 
      this.columnHeader3 = new System.Windows.Forms.ColumnHeader(); 
      this.columnHeader4 = new System.Windows.Forms.ColumnHeader(); 
      this.columnHeader5 = new System.Windows.Forms.ColumnHeader(); 
      this.columnHeader6 = new System.Windows.Forms.ColumnHeader(); 
      this.SuspendLayout(); 
      // 
      // listView1 
      // 
      this.listView1.AutoArrange = false; 
      this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { 
     this.columnHeader1, 
     this.columnHeader2, 
     this.columnHeader3, 
     this.columnHeader4, 
     this.columnHeader5, 
     this.columnHeader6}); 
      this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; 
      this.listView1.FullRowSelect = true; 
      this.listView1.HideSelection = false; 
      this.listView1.Location = new System.Drawing.Point(0, 0); 
      this.listView1.Name = "listView1"; 
      this.listView1.Size = new System.Drawing.Size(1032, 388); 
      this.listView1.TabIndex = 0; 
      this.listView1.UseCompatibleStateImageBehavior = false; 
      this.listView1.View = System.Windows.Forms.View.Details; 
      this.listView1.VirtualListSize = 100000; 
      this.listView1.VirtualMode = true; 
      this.listView1.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.listView1_RetrieveVirtualItem); 
      // 
      // columnHeader1 
      // 
      this.columnHeader1.Width = 92; 
      // 
      // columnHeader2 
      // 
      this.columnHeader2.Width = 405; 
      // 
      // Form1 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(1032, 388); 
      this.Controls.Add(this.listView1); 
      this.Name = "Form1"; 
      this.Text = "Form1"; 
      this.WindowState = System.Windows.Forms.FormWindowState.Maximized; 
      this.ResumeLayout(false); 

     } 

     #endregion 

     private FlickerFreeListView listView1; 
     private System.Windows.Forms.ColumnHeader columnHeader1; 
     private System.Windows.Forms.ColumnHeader columnHeader2; 
     private System.Windows.Forms.ColumnHeader columnHeader3; 
     private System.Windows.Forms.ColumnHeader columnHeader4; 
     private System.Windows.Forms.ColumnHeader columnHeader5; 
     private System.Windows.Forms.ColumnHeader columnHeader6; 
    } 
} 
+0

Avez-vous les derniers pilotes graphiques installés pour votre carte? –

+0

Derniers pilotes graphiques installés. Ce problème peut être reproduit sur chaque machine. – DxCK

+0

Comment remplissez-vous les éléments de la liste? Pouvez-vous afficher le code que vous utilisez pour remplir les éléments listview? –

Répondre

4

Je mesure un slowd propre sur ce code, XP dessine la liste en environ 47 msec, Win7 a besoin d'environ 96 msec, environ deux fois plus lent. Je ne sais pas si cela mérite le surnom de «l'enfer». Je ne sais pas ce qui le cause, mais ne doutez pas qu'Aero a quelque chose à voir avec ça. L'éteindre n'est pas vraiment une option souhaitable.

Heureusement, vous avez fait une erreur dans votre code, qui coûte 48 msec dans mes mesures. Vous rendre la performance exacte que vous aviez sur XP. Vous réutilisez le même ListViewItem, vous êtes supposé en créer un nouveau. Ajouter cette ligne de code au gestionnaire d'événements RetrieveVirtualItem:

private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) 
    { 
     var _item = new ListViewItem(new string[6]); 
     // etc... 
    } 

Et se débarrasser du champ.

+0

Essayé celui-ci, ne voyez pas de différence. – DxCK

+0

Hmm, ce repro-x sur XP et Win7. Je ne peux pas voir ce que vous voyez, le mesurer en remplaçant WndProc() et en utilisant Stopwatch pour mesurer le temps pour m.Msg == 15. –

1

Essayez de changer la ligne SetStyle à:

base.SetStyle(ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); 

UserPaint -

"Si cela est vrai, les peintures de contrôle se plutôt que le système d'exploitation faisant si" (MSDN)

.

+0

Avoir vu un comportement étrange lors de l'utilisation de ControlStyles.UserPaint pour un ListView dessiné par le propriétaire. Je suggère que l'on utilise la propriété DoubleBuffered sur le ListView (est protégé donc on doit hériter et ensuite le définir dans le constructeur). –

0

Essayez d'utiliser WS_EX_COMPOSITED, il améliore les performances de la liste virtuelle un peu:

protected override CreateParams CreateParams 
{ 
    get 
    { 
     CreateParams cp = base.CreateParams; 
     cp.ExStyle |= 0x02000000; 
     return cp; 
    } 
} 

Modifié: Au moins il réduit les artefacts de dessin.