2012-02-05 71 views
0

我一直在尋找一種方式來做到這一點,沒有太大的成功,所以這裏是問題。c#更新列表框沒有'滯後'

如何將項目添加到單獨的線程中的列表框,以便它不凍結ui? 每次添加到列表框時大約有5-15k項目,並且每次凍結ui 5-12秒。

表單有4個列表框,首先創建這些列表框的信息,並將其添加到2D數組(這樣做可以更容易地跟蹤屬於一行的所有信息)。之後我遍歷該2D數組,將1行中的4列添加到它的相應列表框中。

例如。

for (int n = 0; n < 7500; n++) 
{ 
    listBox1.Items.Add(itemList[n, 0].ToString()); 
    listBox2.Items.Add(itemList[n, 1].ToString()); 
    listBox3.Items.Add(itemList[n, 2].ToString()); 
    listBox4.Items.Add(itemList[n, 3].ToString()); 
} 

如前所述,如何使用其他線程比UI更新這些列表框,以防止UI

+2

確定一個普通的listbox是向用戶顯示*一千五百個項目的最佳UI嗎?他們無法一次查看所有這些列表。 – 2012-02-05 20:02:01

+0

我想顯示那麼多項目的原因是爲了調試目的,以檢查信息是否真的是全部正確的,以及我期望的結果。這個程序稍後將被整合到其他程序中,而不會顯示它的項目。我只是好奇如何做到這一點,如果有可能的話(事實證明它是這樣)。但是我會看看Listviews – Raskaroth 2012-02-05 20:22:05

回答

4

您可以採取不同的方法,而改用虛擬ListView。當ListView是「虛擬」時,您負責維護項目列表並告訴ListView在繪畫事件上顯示什麼。這樣,您可以以任何線程安全的方式更新列表,而ListView只會向您詢問「在屏幕上繪製什麼」而不是完整的項目列表。這實際上是獲得所有物品清單非常昂貴時的首選方法。

參見VirtualMode文檔:

http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.virtualmode.aspx

更新:既然你提到,你需要它來完成調試我也建議你使用調試輸出(Debug.WriteLine()),這可能是更適合這份工作。它已經過優化,它是線程安全的,它不會阻塞任何東西,但最好的部分是它不會影響發佈版本的性能。

如果您需要更高性能的輸出,您可以將調試輸出重定向到您喜歡的任何位置。

+0

謝謝!我會研究這個,唯一的原因,我想知道是否有更好的方式顯示它,快速沒有滯後。只是爲了讓我知道。不要向用戶展示,因爲他們永遠不會看到它。 – Raskaroth 2012-02-05 20:24:59

+0

請看看我的編輯。 – 2012-02-05 20:42:59

+0

謝謝,這更好。 – Raskaroth 2012-02-06 13:27:19

2

那本來就不可能不必要的凍結。
您只能從UI線程操縱UI。 (UI不是線程安全的)

通過調用BeginUpdate()EndUpdate(),可以使其更快,並且可以通過在虛擬模式下使用ListView使其更快(但更難)。

但是,您不應該在lsitbox中顯示15,000個項目。
這樣的列表框在實際使用中將毫無用處。

+0

ListBox不支持虛擬模式。看到我的答案。 – 2012-02-05 20:09:23

1
listBox1.BeginUpdate(); 
listBox2.BeginUpdate(); 
listBox3.BeginUpdate(); 
listBox4.BeginUpdate(); 

for (int n = 0; n < 7500; n++) 
{ 
    listBox1.Items.Add(itemList[n, 0].ToString()); 
    listBox2.Items.Add(itemList[n, 1].ToString()); 
    listBox3.Items.Add(itemList[n, 2].ToString()); 
    listBox4.Items.Add(itemList[n, 3].ToString()); 
} 


listBox1.EndUpdate(); 
listBox2.EndUpdate(); 
listBox3.EndUpdate(); 
listBox4.EndUpdate(); 

這將延遲圖紙,直到所有物品已被添加,所以應該會更快。

1

你應該嘗試使用BeginUpdate/EndUpdate方法:

listbox1.BeginUpdate(); 
// Adds 5K items 
listbox1.EndUpdate(); 
1

可以顯著加快通過防止ListBox從後重新繪製這個過程的每一個通過包裝for循環補充:

listBox1.BeginUpdate(); 
listBox2.BeginUpdate(); 
listBox3.BeginUpdate(); 
listBox4.BeginUpdate(); 
for (int n = 0; n < 7500; n++) 
{ 
    listBox1.Items.Add(itemList[n, 0].ToString()); 
    listBox2.Items.Add(itemList[n, 1].ToString()); 
    listBox3.Items.Add(itemList[n, 2].ToString()); 
    listBox4.Items.Add(itemList[n, 3].ToString()); 
} 
listBox1.EndUpdate(); 
listBox2.EndUpdate(); 
listBox3.EndUpdate(); 
listBox4.EndUpdate(); 
+0

+1,答案似乎對我來說足夠了。也有興趣知道downvote的原因。 – 2012-02-05 20:17:23

+0

我沒有downvote,但我懷疑這是因爲你之前的其他職位。這是同時發佈的。 – Raskaroth 2012-02-05 20:19:18

0

我只是想把每個人的答案都放在一起。你應該真的更新你的GUI線程中的項目,否則你可能會得到意想不到的結果。爲了保證代碼在GUI線程中運行,並且您的列表不會像每次添加()一樣重新自我繪製,您需要像其他人一樣發佈的BeingUpdate()和EndUpdate()對,但要在GUI線程中運行它,請使用BeingInvoke(),它簡單地將任務放在「GUI線程隊列」上供消耗。 BeingInvoke()將立即返回,但您的請求將被放入隊列中。

BeingInvoke()API Doc。 http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx

A good discussion on BeginInvoke()及其使用原因。

BeginInvoke((MethodInvoker)delegate 
{ 
    listBox1.BeginUpdate(); 
    listBox2.BeginUpdate(); 
    listBox3.BeginUpdate(); 
    listBox4.BeginUpdate(); 
    for (int n = 0; n < 7500; n++) 
    { 
     listBox1.Items.Add(itemList[n, 0].ToString()); 
     listBox2.Items.Add(itemList[n, 1].ToString()); 
     listBox3.Items.Add(itemList[n, 2].ToString()); 
     listBox4.Items.Add(itemList[n, 3].ToString()); 
    } 
    listBox1.EndUpdate(); 
    listBox2.EndUpdate(); 
    listBox3.EndUpdate(); 
    listBox4.EndUpdate(); 
});