甚至在UI线程上执行时的跨线程操作

laz*_*azo 2 c# multithreading invoke winforms

我有一个函数,它向父控件添加一个控件,该控件从与创建控件的线程不同的线程调用.这是怎么回事:

1        delegate void AddControlToParentDelegate(Control child, Control parent);
2        private void addControlToParent(Control child, Control parent) {
3        if (parent.InvokeRequired) {
4            AddControlToParentDelegate d = new  AddControlToParentDelegate(addControlToParent);
5            this.Invoke(d, new object[] { child, parent });
6            } else {
7                parent.Controls.Add(child);
8            }
9        }
10    }
Run Code Online (Sandbox Code Playgroud)

这既可以正常工作,也parent.InvokeRequired可以正常child.InvokeRequired.然后,一旦执行第5行(现在d调用委托并且该函数应该在UI线程上运行.(对吗?))child第7行引发跨线程操作无效异常.为什么是这样?它已经在它创建的线程上运行了吗?

我设法通过添加额外的(child.InvokeRequired)检查来解决这个问题:

delegate void AddControlToParentDelegate(Control child, Control parent);
private void addControlToParent(Control child, Control parent) {
    if (parent.InvokeRequired) {
        AddControlToParentDelegate d = new AddControlToParentDelegate(addControlToParent);
        this.Invoke(d, new object[] { child, parent });
    } else {
        if (child.InvokeRequired) {
            this.Invoke(new MethodInvoker(delegate() {
            parent.Controls.Add(child);
            }));
        } else {
            parent.Controls.Add(child);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但这似乎非常黑客和不必要.这是这样做的吗?或者我完全错过了公共汽车?

dth*_*rpe 6

请注意,当控件没有窗口句柄时,InvokeRequired不可靠.对于新创建的没有父级的子控件几乎肯定会出现这种情况,这似乎是"固定"代码中的情况.

请参阅Ivan Krivyakov的详细分析:http://www.ikriv.com/en/prog/info/dotnet/MysteriousHang.html

  • 此外,*不*使用`InvokeRequired`的设计更易于维护.我建议将一个`Task`安排到ui线程或使用`BackgroundWorker.ReportProgress`,这两个都是独立于平台的解决方案(即,不依赖于Windows Forms). (3认同)