我有一个Dictionary
与对strings
和Bitmaps
对应的ListView
控件,该控件列出了所有图像键以及其他信息。当列表视图的索引更改时,我还有一个PictureBox
必须显示字典的相应图像。多选设置为假。DateTime
那里是为了确保仅加载最新的“选定”图像。
当索引更改时,会随机发生以下情况之一:
- 图片加载正确
- 不会发生变化
Picturebox
- 抛出 System.ArgumentException。异常总是在同一行抛出(见代码)
如何防止 #2 和 #3 发生?
这是代码:
private Dictionary<string, Bitmap> dictionary;
private ReaderWriterLockSlim dictionary_lock;
private DateTime _LAST_PREVIEW_UPDATE;
private DateTime LAST_PREVIEW_UPDATE
{
get { return _LAST_PREVIEW_UPDATE; }
set
{
if(value.CompareTo(_LAST_PREVIEW_UPDATE) < 0)
_LAST_PREVIEW_UPDATE = value;
}
}
/* ... */
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.listView1.SelectedItems.Count != 1)
return;
DateTime now = DateTime.Now;
string image_code = this.listView1.SelectedItems[0].SubItems[0].Text;
Thread t = new Thread(() =>
{
Bitmap image = null;
bool load_properly;
dictionary_lock.EnterReadLock();
try
{
load_properly = dictionary.TryGetValue(image_code, out image);
}
finally
{
dictionary_lock.ExitReadLock();
}
if (!load_properly)
{
/* LOG THE ERROR */
return;
}
this.BeginInvoke((MethodInvoker)delegate
{
if (now.CompareTo(LAST_PREVIEW_UPDATE) > 0)
{
LAST_PREVIEW_UPDATE = now;
if (picturebox.Image != null)
picturebox.Image.Dispose();
picturebox.Image = image; // This throws the exception
}
});
});
lock (picturebox)
{
t.Start();
t.Join(3000);
}
}
编辑:这是调用堆栈
System.Drawing.dll!System.Drawing.Image.FrameDimensionsList.get() + 0x258 bytes
System.Drawing.dll!System.Drawing.ImageAnimator.CanAnimate(System.Drawing.Image image) + 0x6d bytes
System.Drawing.dll!System.Drawing.ImageAnimator.ImageInfo.ImageInfo(System.Drawing.Image image) + 0x26 bytes
System.Drawing.dll!System.Drawing.ImageAnimator.Animate(System.Drawing.Image image, System.EventHandler onFrameChangedHandler) + 0x97 bytes
System.Windows.Forms.dll!System.Windows.Forms.PictureBox.Animate(bool animate) + 0x65 bytes
System.Windows.Forms.dll!System.Windows.Forms.PictureBox.InstallNewImage(System.Drawing.Image value, System.Windows.Forms.PictureBox.ImageInstallationType installationType) + 0xc8 bytes
> Application.exe!Application.FrmMain.listView1_SelectedIndexChanged.AnonymousMethod__a() Line 596 + 0x78 bytes C#
EDIT2:我想实现之前解释的功能,但这是我能得到的更好的方法。直接从 UI 线程调用太慢(显然),所以我尝试从另一个线程执行它。我希望图像代表列表视图上最后一个选定的项目,但简单地调用线程可能(并且会)导致竞争条件,所以我需要一种机制来防止/丢弃旧的选定索引更改图像,所以只有最后一个选定的索引决定加载哪个图像。
谢谢你的时间!