簡體   English   中英

為什么Listbox.Drawitem被多次調用?

[英]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的可視方面發生更改時發生。

因此,這意味着每次添加項目時,都會調用此事件。 此外,我認為即使你在這個方法中執行某些繪圖操作,它也會調用自身(你可能能夠在更新時使用列表框上的SuspendLayoutResumeLayout來避免這種情況),但我不確定。

據我所知,這是踢球者。 每次觸發此事件時,它幾乎都是列表中的每個項目。 (這可能很有用,因為你可以對以前選擇的項目進行去色處理,所以不要直接跳到我要建議的內容而不考慮它)。 因此,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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM