web-dev-qa-db-fra.com

c # scintillement Listview lors de la mise à jour

J'ai une vue de liste qui est périodiquement mise à jour (toutes les 60 secondes). C'était ennuyeux pour moi que j'obtienne un scintillement à chaque fois qu'il était mis à jour. 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 que j'écrirais directement dans la cellule avec le nouveau texte. Est-ce une meilleure approche ou est-ce que quelqu'un a une meilleure solution.

50
Brad

Le contrôle ListView a un problème de scintillement. Le problème semble être que la surcharge de mise à jour du contrôle est incorrectement implémentée de sorte qu'il agit comme un rafraîchissement. Une mise à jour doit entraîner le contrôle à redessiner uniquement ses régions non valides tandis qu'une actualisation redessine la zone cliente entière du contrôle. Donc, si vous deviez changer, par exemple, la couleur d'arrière-plan d'un élément de la liste, seul cet élément particulier devrait être repeint. Malheureusement, le contrôle ListView semble être d'un avis différent et veut repeindre toute sa surface chaque fois que vous jouez avec un seul élément… même si l'élément n'est pas actuellement affiché. Donc, de toute façon, vous pouvez facilement supprimer le scintillement en lançant le vôtre 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

90
Stormenet

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

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

Voici ma solution rapide pour une implémentation C # qui ne nécessite pas de sous-classer les vues de liste, etc.

Utilise la réflexion pour définir la propriété DoubleBuffered à essayer dans le constructeur de formulaires.

    lvMessages
        .GetType()
        .GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
        .SetValue(lvMessages, true, null);
8
WraithNath

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

5
Gonzalo Quero

Si cela peut vous 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 fais la manipulation 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é)

5
Sebastien GISSINGER

Excellente question et la réponse de Stormenent était parfaite. Voici un port C++ de son code pour toute autre personne qui 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);
        }
    }

};
4
Jon Cage

La solution la plus simple consisterait probablement à utiliser

       listView.Items.AddRange(listViewItems.ToArray());

au lieu de

       foreach (ListViewItem listViewItem in listViewItems)
       {
           listView.Items.Add(listViewItem);
       }

Cela fonctionne bien mieux.

3
Sifty

Vous pouvez utiliser la classe d'extension suivante pour définir la propriété DoubleBuffered sur true:

using System.Reflection;

public static class ListViewExtensions
{
    public static void SetDoubleBuffered(this ListView listView, bool value)
    {
        listView.GetType()
            .GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic)
            .SetValue(listView, value);
    }
}
2
Ghost4Man

Solution simple

yourlistview.BeginUpdate()

//Do your update of adding and removing item from the list

yourlistview.EndUpdate()
1
jaiveeru

Pour ce que ça vaut, dans mon cas, j'ai simplement dû ajouter un appel à

Application.EnableVisualStyles ()

avant d'exécuter l'application, comme ceci:

    private static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new Form1());
    }

Sinon, la double mise en mémoire tampon ne suffit pas. C'était peut-être un très vieux projet et les nouveaux ont ce paramètre par défaut ...

0
Fred Mauroy

Je sais que c'est une extrêmement vieille question et réponse. Cependant, c'est le meilleur résultat lors de la recherche de "C++/cli listview scintillement" - malgré le fait qu'il ne s'agit même pas de C++. Voici donc la version C++ de ceci:

Je l'ai mis dans le fichier d'en-tête de mon formulaire principal, vous pouvez choisir de le mettre ailleurs ...

static void DoubleBuffer(Control^ control, bool enable) {
    System::Reflection::PropertyInfo^ info = control->GetType()->
        GetProperty("DoubleBuffered", System::Reflection::BindingFlags::Instance 
            | System::Reflection::BindingFlags::NonPublic);
    info->SetValue(control, enable, nullptr);
}

S'il vous arrive d'atterrir ici à la recherche d'une réponse similaire pour le C++ managé, cela fonctionne pour moi. :)

0
Chris Parker

Dans Winrt Windows Phone 8.1, vous pouvez définir le code suivant pour résoudre ce problème.

<ListView.ItemContainerTransitions>
    <TransitionCollection/>      
</ListView.ItemContainerTransitions>
0
Suresh Balaraman

Essayez de définir la propriété à double tampon sur true.

Vous pouvez également utiliser:

this.SuspendLayout();

//update control

this.ResumeLayout(False);

this.PerformLayout();
0
Ironicnet

Cela a fonctionné le mieux pour moi.
Puisque vous modifiez directement la cellule, la meilleure solution dans votre cas serait de simplement actualiser/recharger cette cellule/ligne particulière au lieu du tableau entier.
Vous pouvez utiliser la méthode RedrawItems(...) qui repeint uniquement la plage spécifiée d'éléments/lignes de la vue de liste.

public void RedrawItems(int startIndex, int endIndex, bool invalidateOnly);

Référence

Cela m'a totalement débarrassé du scintillement complet de la liste pour moi.
Seul l'élément/enregistrement correspondant scintille lors de la mise à jour.

À votre santé!

0
murphy1310