c # мерцание Listview при обновлении - PullRequest
49 голосов
/ 14 января 2009

У меня есть представление списка, которое периодически обновляется (каждые 60 секунд). Мне было досадно, что я буду мерцать каждый раз, когда это от даты. Используемый метод должен был очистить все элементы и затем воссоздать их. Я решил вместо того, чтобы очистить элементы, которые я бы просто записал прямо в ячейку с новым текстом. Это лучший подход или у кого-то есть лучшее решение?

Ответы [ 13 ]

88 голосов
/ 14 января 2009

Элемент управления ListView имеет проблему мерцания. Кажется, проблема в том, что перегрузка Update элемента управления неправильно реализована, поэтому она действует как Refresh. При обновлении элемент управления должен перерисовывать только свои недопустимые области, а элемент «Обновить» перерисовывает всю клиентскую область элемента управления. Таким образом, если вы хотите изменить, скажем, цвет фона одного элемента в списке, то нужно перекрасить только этот конкретный элемент. К сожалению, элемент управления ListView кажется другого мнения и хочет перекрасить всю свою поверхность всякий раз, когда вы связываетесь с одним элементом ... даже если элемент в данный момент не отображается. Таким образом, в любом случае, вы можете легко подавить мерцание, свернув свое собственное следующим образом:

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);
        }
    }
}

От: Geekswithblogs.net

22 голосов
/ 14 января 2009

В дополнение к другим ответам, многие элементы управления имеют метод [Begin|End]Update(), который можно использовать для уменьшения мерцания при редактировании содержимого, например:

    listView.BeginUpdate();
    try {
        // listView.Items... (lots of editing)
    } finally {
        listView.EndUpdate();
    }
5 голосов
/ 14 января 2009

Да, сделайте это двойным буфером. Это уменьшит мерцание;) http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.doublebuffered.aspx

4 голосов
/ 22 февраля 2017

Вот мое быстрое исправление для реализации C #, которая не требует создания подклассов представлений списка и т. Д.

Использует отражение, чтобы задать свойство DoubleBuffered для использования в конструкторе форм.

    lvMessages
        .GetType()
        .GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
        .SetValue(lvMessages, true, null);
4 голосов
/ 17 декабря 2012

Если это может помочь, следующий компонент решил мои проблемы с мерцанием ListView с .NET 3.5

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

Я использую его в сочетании с методами .BeginUpdate () и .EndUpdate (), где я делаю манипуляции с ListView.Items.

Я не понимаю, почему это свойство защищено ... даже в .NET 4.5 (возможно, проблема безопасности)

4 голосов
/ 15 июля 2010

Отличный вопрос, и ответ Сторменента был на месте. Вот порт C ++ его кода для всех, кто может заниматься реализацией 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);
        }
    }

};
3 голосов
/ 08 мая 2015

Самое простое решение, вероятно, будет использовать

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

вместо

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

Это работает намного лучше.

2 голосов
/ 27 апреля 2018

Вы можете использовать следующий класс расширений, чтобы установить для свойства DoubleBuffered значение 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);
    }
}
1 голос
/ 20 августа 2014

Простое решение

yourlistview.BeginUpdate()

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

yourlistview.EndUpdate()
0 голосов
/ 28 апреля 2018

Для чего это стоит, в моем случае мне просто нужно было добавить вызов на

Application.EnableVisualStyles ()

перед запуском приложения, например:

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

В противном случае двойной буферизации недостаточно. Может быть, это был очень старый проект, и у новых есть такая настройка по умолчанию ...

...