У меня есть список, который периодически обновляется (каждые 60 секунд). Мне было неприятно, что я получаю мерцание каждый раз, когда он устареет. Используемый метод состоял в том, чтобы очистить все элементы, а затем воссоздать их. Я решил вместо очистки элементов, которые я просто напишу прямо в ячейку с новым текстом. Это лучший подход или у кого-то есть лучшее решение.
С# мерцающий список в обновлении
Ответ 1
Элемент управления ListView имеет проблему мерцания. Проблема заключается в том, что контрольная перегрузка обновления неправильно реализована так, что она действует как Refresh. Обновление должно привести к тому, что элемент управления будет перерисовывать только недопустимые регионы, тогда как 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 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);
}
}
}
Ответ 2
В дополнение к другим ответам многие элементы управления имеют метод [Begin|End]Update()
, который можно использовать для уменьшения мерцания при редактировании содержимого - например:
listView.BeginUpdate();
try {
// listView.Items... (lots of editing)
} finally {
listView.EndUpdate();
}
Ответ 3
Да, сделайте его двойным буфером. Это уменьшит мерцание;) http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.doublebuffered.aspx
Ответ 4
Превосходный вопрос и ответ Шторма. Здесь С++-порт его кода для всех, кто может заниматься реализацией С++/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 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);
}
}
};
Ответ 5
Если это может помочь, следующий компонент решил мои проблесковые ошибки 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 (возможно, проблема с безопасностью)
Ответ 6
Простейшим решением, вероятно, будет использование
listView.Items.AddRange(listViewItems.ToArray());
вместо
foreach (ListViewItem listViewItem in listViewItems)
{
listView.Items.Add(listViewItem);
}
Это работает лучше.
Ответ 7
Простое решение
yourlistview.BeginUpdate()
//Do your update of adding and removing item from the list
yourlistview.EndUpdate()
Ответ 8
Попробуйте установить свойство двойной буферизации в true.
Также вы можете использовать:
this.SuspendLayout();
//update control
this.ResumeLayout(False);
this.PerformLayout();
Ответ 9
Я знаю, что это очень старый вопрос и ответ. Однако это самый лучший результат при поиске "С++/cli listview flicker" - несмотря на то, что это даже не говорит о С++. Итак, здесь версия С++:
Я помещаю это в файл заголовка для своей основной формы, вы можете поместить его в другое место...
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);
}
Если вам посчастливилось приземлиться здесь, чтобы найти аналогичный ответ для управляемого С++, это работает для меня.:)
Ответ 10
В Winrt Windows phone 8.1 вы можете установить следующий код, чтобы исправить эту проблему.
<ListView.ItemContainerTransitions>
<TransitionCollection/>
</ListView.ItemContainerTransitions>
Ответ 11
Вот мое быстрое исправление для реализации С#, которая не требует подклассификации видов списка и т.д.
Использует отражение, чтобы установить свойство DoubleBuffered, чтобы попробовать в конструкторе форм.
lvMessages
.GetType()
.GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.SetValue(lvMessages, true, null);