Comment empêcher le scintillement dans ListView lors de la mise à jour d'un texte ListViewItem unique?

StackOverflow https://stackoverflow.com/questions/87795

  •  01-07-2019
  •  | 
  •  

Question

Tout ce que je veux, c'est mettre à jour le texte d'un ListViewItem sans voir de scintillement.

Ceci est mon code de mise à jour (appelé plusieurs fois):

listView.BeginUpdate();
listViewItem.SubItems[0].Text = state.ToString();    // update the state
listViewItem.SubItems[1].Text = progress.ToString(); // update the progress
listView.EndUpdate();

J'ai déjà vu des solutions qui impliquent de remplacer le WndProc (): du composant

protected override void WndProc(ref Message m)
{
    if (m.Msg == (int)WM.WM_ERASEBKGND)
    {
        m.Msg = (int)IntPtr.Zero;
    }
    base.WndProc(ref m);
}

Ils disent que cela résout le problème, mais dans mon cas, cela n'a pas . Je pense que c’est parce que j’utilise des icônes pour chaque élément.

Était-ce utile?

La solution 2

Pour terminer cette question, voici une classe d'assistance qui doit être appelée lors du chargement du formulaire pour chaque contrôle ListView ou tout autre contrôle dérivé de ListView dans votre formulaire. Merci à "Brian Gillespie" pour donner la solution.

public enum ListViewExtendedStyles
{
    /// <summary>
    /// LVS_EX_GRIDLINES
    /// </summary>
    GridLines = 0x00000001,
    /// <summary>
    /// LVS_EX_SUBITEMIMAGES
    /// </summary>
    SubItemImages = 0x00000002,
    /// <summary>
    /// LVS_EX_CHECKBOXES
    /// </summary>
    CheckBoxes = 0x00000004,
    /// <summary>
    /// LVS_EX_TRACKSELECT
    /// </summary>
    TrackSelect = 0x00000008,
    /// <summary>
    /// LVS_EX_HEADERDRAGDROP
    /// </summary>
    HeaderDragDrop = 0x00000010,
    /// <summary>
    /// LVS_EX_FULLROWSELECT
    /// </summary>
    FullRowSelect = 0x00000020,
    /// <summary>
    /// LVS_EX_ONECLICKACTIVATE
    /// </summary>
    OneClickActivate = 0x00000040,
    /// <summary>
    /// LVS_EX_TWOCLICKACTIVATE
    /// </summary>
    TwoClickActivate = 0x00000080,
    /// <summary>
    /// LVS_EX_FLATSB
    /// </summary>
    FlatsB = 0x00000100,
    /// <summary>
    /// LVS_EX_REGIONAL
    /// </summary>
    Regional = 0x00000200,
    /// <summary>
    /// LVS_EX_INFOTIP
    /// </summary>
    InfoTip = 0x00000400,
    /// <summary>
    /// LVS_EX_UNDERLINEHOT
    /// </summary>
    UnderlineHot = 0x00000800,
    /// <summary>
    /// LVS_EX_UNDERLINECOLD
    /// </summary>
    UnderlineCold = 0x00001000,
    /// <summary>
    /// LVS_EX_MULTIWORKAREAS
    /// </summary>
    MultilWorkAreas = 0x00002000,
    /// <summary>
    /// LVS_EX_LABELTIP
    /// </summary>
    LabelTip = 0x00004000,
    /// <summary>
    /// LVS_EX_BORDERSELECT
    /// </summary>
    BorderSelect = 0x00008000,
    /// <summary>
    /// LVS_EX_DOUBLEBUFFER
    /// </summary>
    DoubleBuffer = 0x00010000,
    /// <summary>
    /// LVS_EX_HIDELABELS
    /// </summary>
    HideLabels = 0x00020000,
    /// <summary>
    /// LVS_EX_SINGLEROW
    /// </summary>
    SingleRow = 0x00040000,
    /// <summary>
    /// LVS_EX_SNAPTOGRID
    /// </summary>
    SnapToGrid = 0x00080000,
    /// <summary>
    /// LVS_EX_SIMPLESELECT
    /// </summary>
    SimpleSelect = 0x00100000
}

public enum ListViewMessages
{
    First = 0x1000,
    SetExtendedStyle = (First + 54),
    GetExtendedStyle = (First + 55),
}

/// <summary>
/// Contains helper methods to change extended styles on ListView, including enabling double buffering.
/// Based on Giovanni Montrone's article on <see cref="http://www.codeproject.com/KB/list/listviewxp.aspx"/>
/// </summary>
public class ListViewHelper
{
    private ListViewHelper()
    {
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr handle, int messg, int wparam, int lparam);

    public static void SetExtendedStyle(Control control, ListViewExtendedStyles exStyle)
    {
        ListViewExtendedStyles styles;
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        styles |= exStyle;
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }

    public static void EnableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // enable double buffer and border select
        styles |= ListViewExtendedStyles.DoubleBuffer | ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
    public static void DisableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // disable double buffer and border select
        styles -= styles & ListViewExtendedStyles.DoubleBuffer;
        styles -= styles & ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
}

Autres conseils

La réponse acceptée fonctionne, mais est assez longue, et dériver du contrôle (comme mentionné dans les autres réponses) juste pour activer la double mise en mémoire tampon est aussi un peu excessif. Mais heureusement, nous avons de la réflexion et pouvons également faire appel à des méthodes internes si nous le souhaitons (mais soyez sûr de ce que vous faites!).

En encapsulant cette approche dans une méthode d'extension, nous aurons une classe assez courte:

public static class ControlExtensions
{
    public static void DoubleBuffering(this Control control, bool enable)
    {
        var method = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);
        method.Invoke(control, new object[] { ControlStyles.OptimizedDoubleBuffer, enable });
    }
}

Ce qui peut facilement être appelé dans notre code:

InitializeComponent();

myListView.DoubleBuffering(true); //after the InitializeComponent();

Et tout le scintillement est parti.

Mettre à jour

Je suis tombé sur cette question et de ce fait, la méthode d'extension devrait (peut-être) mieux être:

public static void DoubleBuffered(this Control control, bool enable)
{
    var doubleBufferPropertyInfo = control.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
    doubleBufferPropertyInfo.SetValue(control, enable, null);
}

La vue liste dans CommonControls 6 (XP ou plus récent) prend en charge la mise en mémoire tampon double. Heureusement, .NET encapsule les derniers CommonControls sur le système. Pour activer la double mise en mémoire tampon, envoyez le message Windows approprié au contrôle ListView.

Voici les détails: http://www.codeproject.com/KB/list/listviewxp.aspx

Dans .NET Winforms 2.0, il existe une propriété protégée appelée DoubleBuffered.

En héritant de ListView, vous pouvez définir cette propriété protégée sur true. Cela activera la double mise en mémoire tampon sans qu'il soit nécessaire d'appeler SendMessage.

La définition de la propriété DoubleBuffered est identique à la définition du style suivant:

listview.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

http://connect.microsoft.com/VisualStudio/feedback/ ViewFeedback.aspx? FeedbackID = 94096

Je sais que cette question est assez ancienne, mais parce que c'est l'un des premiers résultats de recherche sur Google, je souhaitais partager mon correctif.

Le seul moyen de supprimer le scintillement à 100% était de combiner la réponse d'Oliver (classe d'extension avec double tampon) et d'utiliser le BeignUpdate () et le EndUpdate () méthodes.

Aucun de ceux qui sont seuls ne pourrait résoudre le scintillement pour moi. Certes, j'utilise une liste très complexe, que je dois ajouter à la liste et la mettre à jour presque toutes les secondes.

cela aidera:

class DoubleBufferedListView : System.Windows.Forms.ListView
{
    public DoubleBufferedListView()
        :base()
    {
        this.DoubleBuffered = true;
    }
}

La solution simple est la suivante:

yourlistview.BeginUpdate ()

// Faites votre mise à jour pour ajouter et supprimer des éléments de la liste

yourlistview.EndUpdate ()

Si vous souhaitez uniquement mettre à jour le texte, définissez simplement le texte du sous-élément modifié directement plutôt que de mettre à jour l'intégralité de ListViewItem (vous n'avez pas indiqué comment vous réalisiez vos mises à jour).

La substitution affichée est équivalente à la substitution de OnPaintBackground, qui serait un "plus correct". manière gérée de faire cette tâche, et ça ne va pas aider pour un seul élément.

Si vous avez toujours des problèmes, nous aurons besoin de précisions sur ce que vous avez réellement essayé.

Ceci est une prise de vue dans le noir, mais vous pouvez essayer de mettre en double tampon le contrôle.

SetStyle(
  ControlStyles.AllPaintingInWmPaint |
  ControlStyles.UserPaint |
  ControlStyles.DoubleBuffer, true)

Appelez la méthode BeginUpdate () sur ListView avant de définir l'un des éléments de la vue liste, puis appelez uniquement EndUpdate () après l'ajout de tous les éléments.

Cela arrêtera le scintillement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top