c#闪烁Listview更新

我有一个定期更新(每60秒)的列表视图。 我感到厌烦的是,每当它过时,我都会闪烁。 正在使用的方法是清除所有的项目,然后重新创build它们。 我决定不用清理项目,而是直接用新文本写入单元格。 这是一个更好的方法,或者没有人有更好的解决scheme。

ListView控件有一个闪烁问题。 问题似乎是控件的Update超载被错误地实现,使得它像一个刷新。 更新应该导致控件只重绘其无效区域,而刷新重绘控件的整个客户区域。 所以,如果你要改变列表中的一个项目的背景颜色,那么只需要重新绘制该特定的项目。 不幸的是,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

除了其他回复之外,许多控件还有一个[Begin|End]Update()方法,可以用来在编辑内容时减less闪烁,例如:

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

优秀的问题和Stormenent的答案是现货。 这里是他的代码的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); } } }; 

如果这可以帮助,下面的组件解决了.NET 3.5的ListView闪烁问题

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

我将它与.BeginUpdate()和.EndUpdate()方法结合使用,我在这里执行ListView.Items操作。

我不明白为什么这个属性是一个受保护的…即使在.NET 4.5(也许是一个安全问题)

最简单的解决scheme可能会使用

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

代替

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

这工作方式更好。

解决scheme简单

 yourlistview.BeginUpdate() //Do your update of adding and removing item from the list yourlistview.EndUpdate() 

尝试设置双缓冲的属性为true。

你也可以使用:

 this.SuspendLayout(); //update control this.ResumeLayout(False); this.PerformLayout(); 

我知道这是一个非常古老的问题和答案。 然而,这是search“C ++ / cli listview flicker”的最好结果 – 尽pipe事实上这甚至不谈论C ++。 所以这里是C ++版本:

我把这个在我的主窗体的头文件中,你可以select把它放在其他地方…

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

如果你碰巧在这里寻找一个类似的托pipeC ++的答案,这对我很有用。 🙂

在Winrt Windows Phone 8.1中,您可以设置以下代码来解决此问题。

 <ListView.ItemContainerTransitions> <TransitionCollection/> </ListView.ItemContainerTransitions> 

这是我的C#实现的快速修复,不需要inheritance列表视图等。

使用reflection设置DoubleBuffered属性在窗体构造函数中尝试。

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