我设置了一个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控件添加到面板后真的是线程安全的吗?
答案 0 :(得分:2)
不,那不行。好吧,至少它不会一直工作。它可能会工作一段时间,但最终会失败,不可挽回和壮观。一般规则是,除了创建它之外的任何其他线程,您无法对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;
}));
}
答案 1 :(得分:2)
不,它不会起作用。 所有 GUI代码必须在相应的用户界面线程上完成。线程上下文不会一直被检查,因此可以编写类似于现在可以工作但在未来的.NET框架更新中失败的内容。
在您的情况下,FileSystemWatcher
了解ISynchronizeInvoke
模式,因此只需将其SynchronizingObject
属性设置为其使用的表单即可。请注意,如果您使用设计器在表单上放置FileSystemWatcher
,则会自动设置此属性。
答案 2 :(得分:1)
在程序开头将Control :: CheckForIllegalCrossThreadCalls设置为true。在这种情况下,使用Windows窗体的每个跨线程操作都会立即崩溃程序。当CheckForIllegalCrossThreadCalls为false时,这比默认的未定义行为更好。