我的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();
}
答案 0 :(得分:1)
如果控件顶部弹出一个对话框,请猜出关闭对话框时控件必须执行的操作?它必须重绘自己!
在查看绘图控件时,尝试使用Debug.Writeline编写调试信息。当然,您仍然需要注意不要将Visual Studio拉到表单顶部!这是两个监视器真正可以提供帮助的情况。
答案 1 :(得分:1)
我不确定这是否必须进行测试,但this article makes me believe that what I am going to say is true.
基本上,如果你去MSDN documentation:
当所有者绘制的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
所以,这实际上会产生一种fibonacci type situation(3个项目导致6个调用... 5个会导致你的15个数字),你可以看到初始加载如何繁琐,以及如何为该方法的n次调用添加一个新项目。
从上面的文章:
ListBox对其中的每个项重复调用DrawItem方法 物品集合。
DrawItem事件处理程序的DrawItemEventArgs参数公开 一个Index属性,其值是要绘制的项的索引。 小心!系统引发DrawItem事件,索引值为 当Items集合为空时为-1。当发生这种情况时,你应该调用DrawItemEventArgs.DrawBackground()和DrawFocusRectangle() 方法然后退出。举起这个活动的目的是为了让 控件绘制一个焦点矩形,以便用户可以告诉它有 焦点,即使没有物品存在。代码陷阱 condition,调用这两个方法,然后退出处理程序 立即