【发布时间】:2010-12-16 17:58:48
【问题描述】:
我有一个表单,上面有我的自定义控件。
我的表单中有一个方法:
private void SetEnabledOnControls(bool val)
{
if (InvokeRequired)
{
Invoke((Action<bool>)SetEnabledOnControls, val);
}
else
{
//do the work - iterate over child controls,
//and they iterate over their children, etc...
}
}
在 else 分支上的方法中,我得到了提到的异常:Cross-thread operation not valid: Control 'txtNumber' accessed from a thread other than the thread it was created on.
我的场景实际上有点复杂 - 我只是将其作为示例进行推断。实际发生的情况是我正在使用 WorkflowFoundation - 我在 WorkflowApplication 中运行 StateMachineActivity (CTP1)(它在它自己的线程中运行),我订阅了它的事件,然后我从那里调用 SetEnabledOnControls。此外,我正在使用书签来恢复我的工作流程(另外,还有 MEF,不参与场景)。
所有这些都与我对 InvokeRequired 的明显误解无关 - 如果 InvokeRequired 为假,我怎么可能有跨线程异常?我没有“手动”创建任何控件——它们都在设计师放置的 Initialize() 中。
有人能解释一下吗?
谢谢!
编辑
使用 GWLlosa 建议,我使用System.Threading.Thread.CurrentThread.ManagedThreadId 跟踪了 ThreadId。现在来了奇怪的部分...... Initialize() 中的线程 id 是 10。在传递前 2 个状态之间,它的 ID 为 13 - InvokeRequired 为真,它被正确调用。但是,在第二个状态之后,当它进入SetEnabledOnControls 时又是 13,但是这次 InvokeRequired 是假的!怎么会!?后来,当然,它无法更改子控件(不足为奇)。会不会是表单以某种方式改变了它所在的线程??
编辑 2 现在我打电话给:
if (IsHandleCreated)
{
Invoke((Action<bool>)SetEnabledOnControls, val);
}
它的IsHandleCreated 为真,但仍然以 devSpeed pointed at 失败。
编辑 3 FACEPALM :) 恢复状态的按钮之一最初是表单的 CancelButton。当它从属性中删除时,codebihind 仍然有 DialogResult=Cancel ——所以我的表单确实正在关闭,当然它缺少句柄,所以 InvokeRequired 没有返回正确的信息,因此出现错误.
谢谢大家!我今天学到了一个新东西:)
【问题讨论】:
标签: c# winforms .net-4.0 thread-safety multithreading