我有一个带有4个PictureBox控件的Winform,每个控件都包含一个不同的图像。这个过程是:
引发事件x,来自此事件的eventargs包含每个图像的文件名(4),依此类推(文件存在等等)。然后,我必须更新UI。
通常我使用Invoke:
Invoke((ThreadStart)delegate()
{
picBig.Image = new Bitmap(strImageBig);
picLittle1.Image = new Bitmap(saLittle[0]);
picLittle2.Image = new Bitmap(saLittle[1]);
picLittle3.Image = new Bitmap(saLittle[2]);
});
// saLittle[] is a string array, contains, filenames: "image1.jpg"
但是当这个执行时,表单会冻结一段时间,大约500ms,我知道这是一个很小的间隔,但它很明显,然后应用程序继续正常。
我试图找出'UI冻结'的原因,然后,经过研究,我找到了BeginInvoke。现在我的代码看起来像这样:
BeginInvoke((MethodInvoker)delegate
{
picBig.Image = new Bitmap(strImageBig);
picLittle1.Image = new Bitmap(saLittle[0]);
picLittle2.Image = new Bitmap(saLittle[1]);
picLittle3.Image = new Bitmap(saLittle[2]);
});
这快一点。但UI仍然会冻结200~300ms。
在我读过的文章中,他们说BeginInvoke比Invoke更好。
代码工作正常,逻辑或其他任何问题都没有问题。我只想知道为什么会这样。我不想不明白这个疑问。该项目已经完成。希望这对其他人有用。
也许这不是正确的做法。我知道有很多方法可以从后台线程更新UI,但还有另一种方法可以使更新更快吗?
或者,你认为,图像加载是什么原因?还有另一种方法可以更快地加载图像吗?
提前致谢。
答案 0 :(得分:4)
这是因为您实际上是在UI线程上从磁盘加载图像以及设置控件的内容。使用文件路径调用Bitmap
构造函数将转到硬盘驱动器并将映像加载到内存中。
Invoke
和BeginInvoke
将运行您在创建控件的线程上提供的委托,最有可能成为UI线程。
...但还有另一种方法可以更快地进行更新吗?
将图像加载到后台线程上,当它们实际加载时,调用并将图像设置为控件。
var big = new Bitmap(strImageBig);
var little1 = new Bitmap(saLittle[0]);
var little2 = new Bitmap(saLittle[1]);
var little3 = new Bitmap(saLittle[2]);
Invoke((ThreadStart)delegate()
{
picBig.Image = big;
picLittle1.Image = little1;
picLittle2.Image = little2;
picLittle3.Image = little3;
});
答案 1 :(得分:0)
但是当这个执行时,表单会冻结一段时间,大约500ms,我知道这是一个很小的间隔,但它很明显,然后应用程序继续正常。
最终,UI线程需要实际更新图像。在UI线程上生成和更新图像时,这将导致(短暂)延迟。