我目前正在开发Windows.Forms应用程序。它基本上是一个简单的运动检测问题。
我在表单上有一个按钮,按下后会启动一个执行以下操作的后台工作程序:
(sender as BackgroundWorker).ReportProgress((Bitmap)buffer.Clone())
在Progress Changed Event中,然后我将缓冲区绘制到屏幕上。
if (!PnlImage.IsDisposed)
PnlImage.CreateGraphics().DrawImageUnscaled(buffer, 0, 0);
我不禁想知道这是否是在屏幕上绘制更新图像的最佳方式。任何人都可以建议我可以做出哪些改进? 感谢。
编辑: 我已经更新了程序以使用.NET Framework 4,我们不再使用BackgroundWorker。相反,我们现在使用System.Threading.Tasks命名空间,并使用Invoke从任务中更新背景图像。
感谢所有回复。
答案 0 :(得分:2)
我相信您可能遇到的任何问题的根源是任何GUI更新都必须在UI线程上完成。您无法安全地从其他线程更新UI。所以,基本上,你需要做类似下面的事情(我只是改变背景颜色作为例子,但你可以做任何你喜欢的事情):
private void SomethingCalledFromBackgroundThread()
{
panel1.Invoke(new DoUpdatePanel(UpdatePanel), Color.Blue);
}
private delegate void DoUpdatePanel(Color aColor);
private void UpdatePanel(Color aColor)
{
panel1.BackColor = aColor;
}
============更新=======>
@Ash你错误地描述了我的答案。我没有说要在ProgressChanged中调用Invoke。 @Jean请记住,ReportProgress / ProgressChanged是异步运行的 - 这就是为什么你发现自己正在复制你的图像。如果您在后台线程中使用Invoke而不是ReportProgress,则不需要这样做。
答案 1 :(得分:1)
我不确定这是否严格正确,但我确信你不能在单独的线程上交叉线程GUI /控制操作,因为它默认在专用的GUI线程上处理。
我之前尝试过类似的事情,最后我决定使用一种完全不同的方法,因为将属性设置为false是让它工作的最糟糕方式。
答案 2 :(得分:1)
ProgressChanged和RunWorkerCompleted事件允许您直接更新UI。只有DoWork事件处理程序才能访问。 See MSDN:
你必须小心不要操纵 你的任何用户界面对象 DoWork事件处理程序。代替, 与用户界面进行通信 通过ProgressChanged和 RunWorkerCompleted事件。
这是使用BackgroundWorker而不是创建自己的线程的主要好处之一。所以TheObjectGuy不正确,你不需要在ProgressChanged中使用BeginInvoke / Invoke。
只要您的图片不是太大,克隆它就不会导致任何严重的性能问题。如果您有疑虑,请使用更大的图像运行一些性能测试。
否则,为了避免使用锁等棘手的同步问题,我认为复制图像是保持简单的好方法。
答案 3 :(得分:1)
使用ProgressChanged事件很好。什么不好是直接画到屏幕上。最小化和恢复表单时,图像将消失。解决方法很简单:
PnlImage.BackgroundImage = buffer;