57 votes

c # scintillant Listview sur mise à jour

J'ai une vue de liste mise à jour périodiquement (toutes les 60 secondes). C'était angoissant pour moi que j'obtienne un scintillement à chaque fois que ce soit en date. La méthode utilisée consistait à effacer tous les éléments, puis à les recréer. J'ai décidé de ne pas effacer les éléments mais d'écrire directement dans la cellule avec le nouveau texte. Est-ce une meilleure approche ou est-ce que quelqu'un a une meilleure solution?

Merci

Brad

100voto

Stormenet Points 8695

Le contrôle ListView a un problème de scintillement. Le problème semble être que le contrôle de la mise à Jour de la surcharge n'est pas correctement mis en œuvre tel qu'il agit comme un Rafraîchissement. Une mise à Jour devrait provoquer le contrôle de redessiner seulement de ses régions non valides alors qu'une Actualisation redessine le contrôle de l'ensemble de la zone client. Donc, si vous aviez à changer, par exemple, la couleur d'arrière-plan d'un élément dans la liste, puis seulement que le point particulier doit être repeint. Malheureusement, le contrôle ListView semble être d'un avis différent et veut repeindre toute sa surface chaque fois que vous salissez avec un seul élément... même si l'élément n'est pas affiché. Donc, de toute façon, vous pouvez facilement supprimer le scintillement en roulement de votre propre comme suit:

class ListViewNF : System.Windows.Forms.ListView
{
    public ListViewNF()
    {
        //Activate double buffering
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

        //Enable the OnNotifyMessage event so we get a chance to filter out 
        // Windows messages before they get to the form's WndProc
        this.SetStyle(ControlStyles.EnableNotifyMessage, true);
    }

    protected override void OnNotifyMessage(Message m)
    {
        //Filter out the WM_ERASEBKGND message
        if(m.Msg != 0x14)
        {
            base.OnNotifyMessage(m);
        }
    }
}

De: Geekswithblogs.net

27voto

Marc Gravell Points 482669

En plus des autres réponses, de nombreux contrôles ont une méthode [Begin|End]Update() que vous pouvez utiliser pour réduire les scintillements lors de la modification du contenu - par exemple:

     listView.BeginUpdate();
    try {
        // listView.Items... (lots of editing)
    } finally {
        listView.EndUpdate();
    }
 

7voto

sgissinger Points 181

Si cela peut aider, le composant suivant a résolu mes problèmes de scintillement ListView avec .NET 3.5

 [ToolboxItem(true)]
[ToolboxBitmap(typeof(ListView))]
public class ListViewDoubleBuffered : ListView
{
    public ListViewDoubleBuffered()
    {
        this.DoubleBuffered = true;
    }
}
 

Je l'utilise en conjonction avec les méthodes .BeginUpdate () et .EndUpdate () où je manipule ListView.Items.

Je ne comprends pas pourquoi cette propriété est protégée ... même dans le .NET 4.5 (peut-être un problème de sécurité)

5voto

Gonzalo Quero Points 2492

Oui, faites-le en double tampon. Cela réduira le scintillement;) http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.doublebuffered.aspx

5voto

Jon Cage Points 14126

Excellente question et la réponse de Stormenent était parfaite. Voici un portage C ++ de son code pour quiconque pourrait s’attaquer aux implémentations C ++ / CLI.

 #pragma once

#include "Windows.h" // For WM_ERASEBKGND

using namespace System;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;

public ref class FlickerFreeListView : public ListView
{
public:
    FlickerFreeListView()
    {
        //Activate double buffering
        SetStyle(ControlStyles::OptimizedDoubleBuffer | ControlStyles::AllPaintingInWmPaint, true);

        //Enable the OnNotifyMessage event so we get a chance to filter out 
        // Windows messages before they get to the form's WndProc
        SetStyle(ControlStyles::EnableNotifyMessage, true);
    }

protected:
    virtual  void OnNotifyMessage(Message m) override
    {
        //Filter out the WM_ERASEBKGND message
        if(m.Msg != WM_ERASEBKGND)
        {
            ListView::OnNotifyMessage(m);
        }
    }

};
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X