2009-01-14 165 views
44

我有一個定期更新(每60秒)的列表視圖。對我而言,每當它變得過時時,我都會感到不適。正在使用的方法是清除所有項目,然後重新創建它們。我決定不使用新文本直接寫入單元格來清除項目。這是一個更好的方法,還是有人有更好的解決方案。c#閃爍Listview更新

回答

77

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

+1

您必須知道,此解決方案(由於雙緩衝)的缺點是更新控件明顯較慢(嘗試添加1000個項目)。 – 2010-07-09 14:04:39

+1

說實話,我從來沒有使用winforms listview。但是,當您調用** SuspendLayout **和** ResumeLayout **時,性能是否會消失? – Stormenet 2010-07-09 15:14:01

+0

謝謝Stormenent。我一直在尋找解決這個問題的一段時間,這對我很好。 – 2011-05-24 08:33:39

0

嘗試設置雙緩衝屬性爲true。

你也可以使用:

this.SuspendLayout(); 

//update control 

this.ResumeLayout(False); 

this.PerformLayout(); 
21

除了對方回覆,許多控件有一個[Begin|End]Update()方法,您可以使用編輯內容時,減少閃爍 - 例如:

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

優秀的問題和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); 
     } 
    } 

}; 
3

如果這能幫助,下列各項組件解決了我的ListView閃爍的問題與.NET 3.5

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

我conjonction與.BeginUpdate()和.EndUpdate(),我做的方法,用它ListView.Items操作。

我不明白爲什麼這個屬性是受保護的一個......即使是在.NET 4.5(可能是安全問題)

1

簡單的解決方案

yourlistview.BeginUpdate() 

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

yourlistview.EndUpdate() 
3

最簡單的解決可能是使用

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

,而不是

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

這種方式更好。

0

我知道這是一個非常舊的問題和答案。但是,這是搜索「C++/cli listview flicker」時的首要結果 - 儘管事實上這甚至沒有談論C++。因此,這裏的C++版本的這個:

我把這個頭文件爲我的主要形式,你可以選擇把它放在別處......

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

如果你碰巧在這裏降落尋找託管C++的類似答案,適用於我。 :)

0

在Winrt Windows Phone 8.1中,您可以設置以下代碼來解決此問題。

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

這裏是我不需要的子類列表視圖等

使用反射來設置DoubleBuffered物業的形式構造嘗試C#實現快速修復。

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