[英]Why does Listbox.Drawitem get called many times?
我在C#WinForm上有一個數據綁定列表框,它包含指向圖像文件位置的鏈接。 我想將圖像顯示為縮略圖,供用戶單擊和查看。 我通過設置DrawMode = OwnerDrawVariable並處理DrawItem和MeasureItem事件使其正常工作。
但是我注意到我必須單擊退出2次以退出應用程序(看起來它在第一次單擊時稱為selectedIndexChanged,然后在第二次退出)。 在進一步檢查時,我注意到當我單擊列表框中的項目(例如15次以上)時,DrawItem事件被多次觸發。 列表框中一次只有1-2個項目! 為什么它被多次調用?
我使用非數據綁定簡單列表框測試了它,它做了同樣的事情。 我只是很好奇,因為我必須從磁盤讀取圖像並獲取它的縮略圖放入列表框,如果它這樣做15-20次可能會影響性能(並且完全沒必要)。
private void listBox1_MeasureItem(object sender, MeasureItemEventArgs e)
{
MessageBox.Show("listBox1_MeasureItem");
// Cast the sender object back to ListBox type.
ListBox theListBox = (ListBox)sender;
// Get the file path contained in each item.
DataRowView drv = (DataRowView)theListBox.Items[e.Index];
string fileString = drv.Row["fullpath"].ToString();
// Create an image object and load image file into it
Image img = Image.FromFile(fileString);
e.ItemHeight = Convert.ToInt32(img.Height * 0.15);
e.ItemWidth = Convert.ToInt32(img.Width * 0.15);
}
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
MessageBox.Show("listBox1_DrawItem");
// If the item is the selected item, then draw the rectangle
// filled in blue. The item is selected when a bitwise And
// of the State property and the DrawItemState.Selected
// property is true.
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
{
e.Graphics.FillRectangle(Brushes.CornflowerBlue, e.Bounds);
}
else
{
// Otherwise, draw the rectangle filled in beige.
e.Graphics.FillRectangle(Brushes.Beige, e.Bounds);
}
DataRowView drv = (DataRowView)listBox1.Items[e.Index];
Image img = Image.FromFile(drv.Row["fullpath"].ToString());
img = img.GetThumbnailImage(e.Bounds.Width, e.Bounds.Height, null, IntPtr.Zero);
e.Graphics.DrawImage(img, e.Bounds.X, e.Bounds.Y);
// Draw the focus rectangle around the selected item.
e.DrawFocusRectangle();
}
如果控件頂部彈出一個對話框,請猜出關閉對話框時控件必須執行的操作? 它必須重繪自己!
在查看繪圖控件時,請嘗試使用Debug.Writeline編寫調試信息。 當然,您仍然需要注意不要將Visual Studio拉到表單頂部! 這是兩個顯示器真正可以提供幫助的情況。
我不確定,這將不得不進行測試,但這篇文章讓我相信我要說的是真的。
基本上,如果你通過MSDN文檔 :
在所有者繪制的ListBox的可視方面發生更改時發生。
因此,這意味着每次添加項目時,都會調用此事件。 此外,我認為即使你在這個方法中執行某些繪圖操作,它也會調用自身(你可能能夠在更新時使用列表框上的SuspendLayout和ResumeLayout來避免這種情況),但我不確定。
據我所知,這是踢球者。 每次觸發此事件時,它幾乎都是列表中的每個項目。 (這可能很有用,因為你可以對以前選擇的項目進行去色處理,所以不要直接跳到我要建議的內容而不考慮它)。 因此,DrawItemEventArgs具有正在繪制的項目的索引。 使用它,您可以專注於您需要繪制的特定項目。 這可能會幫助您重新處理已經處理過的內容(請記住上面文章中的注釋...如下所示,關於索引允許為-1)。
要想象這個過程:
Add 1 item ->DrawItem
Add 2nd item->DrawItem
->DrawItem
Add 3rd item->DrawItem
->DrawItem
->DrawItem
Add nth item->DrawItem * n
所以,這實際上導致了一種斐波那契類型的情況 (3個項目導致6個調用... 5個將導致你的15個數字),你可以看到初始加載如何繁瑣,以及如何添加新項目對n調用方法。
從上面的文章:
ListBox對其Items集合中的每個項重復調用DrawItem方法。
DrawItem事件處理程序的DrawItemEventArgs參數公開一個Index屬性,其值是要繪制的項的索引。 小心! 當Items集合為空時,系統引發DrawItem事件,索引值為-1。 當發生這種情況時,您應該調用DrawItemEventArgs.DrawBackground()和DrawFocusRectangle()方法,然后退出。 引發事件的目的是讓控件繪制一個焦點矩形,以便用戶可以告訴它具有焦點,即使沒有項目存在。 該條件的代碼陷阱,調用這兩個方法,然后立即退出處理程序
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.