在单独的线程上添加控件后,对WinForm控制线程安全感到好奇

时间:2010-07-13 18:19:17

标签: c# winforms thread-safety

我设置了一个FileSystemWatcher来获取将在特定目录中删除的图片。我处理它的方式是在停靠在面板内的代码中添加PictureBox。我跑了它,它爆炸了,我意识到我没有正确处理与主线程上的控件的交互。这是代码:

        PictureBox pb = new PictureBox();
        pnlCapturePicture.Controls.Add(pb);
        pb.Dock = DockStyle.Fill;
        pb.ImageLocation = photopath;

现在我明白了如何[线程安全调用Windows窗体控件] [1]但我很好奇我是否只是使Panel添加线程安全我真的完成了什么?

说我是否这样做了:

        PictureBox pb = new PictureBox();
        AddControlThreadSafe(pb);
        pb.Dock = DockStyle.Fill;
        pb.ImageLocation = photopath;

将PictureBox控件添加到面板后真的是线程安全的吗?

3 个答案:

答案 0 :(得分:2)

不,那不行。好吧,至少它不会一直工作。它可能会工作一段时间,但最终会失败,不可挽回和壮观。一般规则是,除了创建它之外的任何其他线程,您无法对FormControl执行任何操作。换句话说,它们具有线程亲和力。你真正需要做的是让主UI线程通过编组消息来创建和修改PictureBox。这可以通过利用ISynchronizeInvoke方法来完成。所有表单和控件都实现了此接口。

public void ThreadMethod()
{
  pnlCapturePicture.Invoke((Action)(() =>
  {
    PictureBox pb = new PictureBox(); 
    pnlCapturePicture.Controls.Add(pb); 
    pb.Dock = DockStyle.Fill; 
    pb.ImageLocation = photopath; 
  }));
}

答案 1 :(得分:2)

不,它不会起作用。 所有 GUI代码必须在相应的用户界面线程上完成。线程上下文不会一直被检查,因此可以编写类似于现在可以工作但在未来的.NET框架更新中失败的内容。

在您的情况下,FileSystemWatcher了解ISynchronizeInvoke模式,因此只需将其SynchronizingObject属性设置为其使用的表单即可。请注意,如果您使用设计器在表单上放置FileSystemWatcher,则会自动设置此属性。

答案 2 :(得分:1)

在程序开头将Control :: CheckForIllegalCrossThreadCalls设置为true。在这种情况下,使用Windows窗体的每个跨线程操作都会立即崩溃程序。当CheckForIllegalCrossThreadCalls为false时,这比默认的未定义行为更好。

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.checkforillegalcrossthreadcalls.aspx