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.
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);
}
}
}
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();
}
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);
Oui, faites-le double tampon. Cela réduira le scintillement;) http://msdn.Microsoft.com/en-us/library/system.windows.forms.listview.doublebuffered.aspx
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é)
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);
}
}
};
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.
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);
}
}
Solution simple
yourlistview.BeginUpdate()
//Do your update of adding and removing item from the list
yourlistview.EndUpdate()
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 ...
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. :)
Dans Winrt Windows Phone 8.1, vous pouvez définir le code suivant pour résoudre ce problème.
<ListView.ItemContainerTransitions>
<TransitionCollection/>
</ListView.ItemContainerTransitions>
Essayez de définir la propriété à double tampon sur true.
Vous pouvez également utiliser:
this.SuspendLayout();
//update control
this.ResumeLayout(False);
this.PerformLayout();
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é!