2009-10-20 13 views
4

Je sais que cela semble compliqué à reproduire, mais s'il vous plaît me suivre:C# ListView en VirtualMode scintille lorsque l'élément sélectionné est pas visible

Vous avez un ListView avec VirtualMode = true.

Sélectionnez un élément, faites défiler vers le bas de sorte que la L'élément sélectionné sort de la zone visuelle et tente ensuite d'ajouter un autre élément à ListView.

Vous verrez que pendant une fraction de seconde il se comporte anormalement et de voir un peu de scintillement. Si vous escaladez la situation et essayez d'ajouter beaucoup d'éléments très rapidement (j'ajoute environ 20 fois par seconde), vous verrez que le petit problème devient très important. C'est une combinaison d'éléments clignotants et invalides autour de là.

J'ai étudié le problème et il semble que ListView génère beaucoup d'événements RetrieveVirtualItem pour l'élément sélectionné (même si ce n'est clairement pas visible).

Il semble que lorsque j'ajoute un nouvel élément (augmentez VirtualListSize), le ListView essaie d'abord de se concentrer sur l'élément sélectionné, puis de revenir à l'emplacement précédent.

Quelqu'un at-il rencontré le même problème?

Répondre

1

Divers contrôles possèdent une propriété DoubleBuffered protégée. Vous pouvez essayer de dériver votre propre DBListView à partir de ListView, et dans son constructeur, définir sa propriété DoubleBuffered sur true.

+0

Depuis un certain temps depuis que j'ai posté la question, je vais essayer de trouver ce projet et essayer votre solution. Merci –

5

Voici une classe dérivée avec contourner ce problème.

Utilisez la méthode SetVirtualListSize() au lieu du VirtualListSize normal.

public class FlickerFreeListView : ListView 
{ 
    #region Static Functionality 

    private static FieldInfo _internalVirtualListSizeField; 

    static FlickerFreeListView() 
    { 
     _internalVirtualListSizeField = typeof(ListView).GetField("virtualListSize", System.Reflection.BindingFlags.NonPublic | BindingFlags.Instance); 

     if (_internalVirtualListSizeField == null) 
     { 
      string msg = "Private field virtualListSize in type System.Windows.Forms.ListView is not found. Workaround is incompatible with installed .NET Framework version, running without workaround."; 
      Trace.WriteLine(msg); 
     } 
    } 

    #endregion 


    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    private static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam); 

    internal IntPtr SendMessage(int msg, IntPtr wparam, IntPtr lparam) 
    { 
     return SendMessage(new HandleRef(this, this.Handle), msg, wparam, lparam); 
    } 

    public void SetVirtualListSize(int size) 
    { 
     // if workaround incompatible with current framework version (usually MONO) 
     if (_internalVirtualListSizeField == null) 
     { 
      VirtualListSize = size; 
     } 
     else 
     { 
      if (size < 0) 
      { 
       throw new ArgumentException("ListViewVirtualListSizeInvalidArgument"); 
      } 

      _internalVirtualListSizeField.SetValue(this, size); 
      if ((base.IsHandleCreated && this.VirtualMode) && !base.DesignMode) 
      { 
       SendMessage(0x102f, new IntPtr(size), new IntPtr(2)); 
      } 
     } 
    } 
} 
+0

Merci pour cela, mais il y a longtemps que j'ai eu le problème. Je ne peux plus tester cette solution. Je vois qu'il a quelques upvotes donc si quelqu'un a testé cela et cela a fonctionné alors écrivez un commentaire ici afin que je puisse accepter cette réponse. –