代码之家  ›  专栏  ›  技术社区  ›  Flory

对WinForm控件在单独线程上添加控件后的线程安全性感兴趣

  •  2
  • Flory  · 技术社区  · 14 年前

    我设置了一个文件系统观察程序来获取将被放到特定目录中的图片。我处理它的方法是在代码中添加一个PictureBox,该代码停靠在面板内部。我运行它,它爆炸了,我意识到我没有正确地处理与主线程上控件的交互。代码如下:

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

    现在我了解了如何对Windows窗体控件进行[线程安全调用][1]但是我很好奇 只是 让面板添加线程安全我真的完成了什么吗?

    如果我这样做:

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

    将PictureBox控件添加到面板后与它交互是否真的是线程安全的?

    3 回复  |  直到 14 年前
        1
  •  2
  •   Stephen Cleary    14 年前

    不,它不起作用。 所有 GUI代码必须在适当的用户界面线程上完成。线程上下文并不是一直处于检查状态,因此可以编写类似的内容,这些内容现在可以工作,但在将来的.NET框架更新中会失败。

    以你为例 FileSystemWatcher 理解 ISynchronizeInvoke 模式,所以只需设置 SynchronizingObject 属性设置为它使用的窗体。注意,如果你把 文件系统监视程序 在使用设计器的窗体上,此属性是自动设置的。

        2
  •  2
  •   Brian Gideon    14 年前

    不,那不行。好吧,至少它不会始终如一地工作。它可能会工作一段时间,但最终会以不可预知和惊人的方式失败。一般规则是你不能对 Form Control 在创建线程以外的任何其他线程上。换句话说,它们具有线程关联性。您真正需要做的是让主UI线程创建和修改 PictureBox 通过将消息编组到其中。这可以通过利用 ISynchronizeInvoke 方法。所有窗体和控件都实现此接口。

    public void ThreadMethod()
    {
      pnlCapturePicture.Invoke((Action)(() =>
      {
        PictureBox pb = new PictureBox(); 
        pnlCapturePicture.Controls.Add(pb); 
        pb.Dock = DockStyle.Fill; 
        pb.ImageLocation = photopath; 
      }));
    }
    
        3
  •  1
  •   Alex F    14 年前

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

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