Chr*_*ott 2 c# multithreading begininvoke winforms
是否有解释Control.BeginInvoke()不执行它传递的委托?
我们在Winforms应用程序中采用了以下模式,以便在UI线程上安全地执行UI相关工作:
private Control hiddenControl = new Control();
private void uiMethod()
{
MethodInvoker uiDelegate = new MethodInvoker(delegate()
{
Logging.writeLine("Start of uiDelegate");
//ui releated operations
childDialog = new ChildDialog();
childDialow.show();
Logging.writeLine("End of uiDelegate");
});
if (hiddenControl.InvokeRequired)
{
Logging.writeLine("Start of InvokeRequired block");
hiddenControl.BeginInvoke(uiDelegate);
Logging.writeLine("End of InvokeRequired block");
}
else
{
uiDelegate();
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们显式创建一个控件"hiddenControl",以便在UI线程上运行委托.我们从不调用endInvoke,因为它显然不是 Control.BeginInvoke所必需的,我们永远不需要返回值,因为我们的方法只是操纵UI,无论如何.
虽然非常冗长,这种格局似乎是一个比较 好 接受的 解决方案.然而,有一些证据表明即使这种模式在所有情况下都不能很好地发挥作用.
我不排除应用程序错误并指责WinForms.毕竟,选择可能不会破碎.然而,我无法解释为什么代表似乎根本没有参与竞选.
在我们的例子中,我们有时会观察到"开始uiDelegate"日志消息从未在某些线程场景中执行,即使"Start of InvokeReqiured block"和"End of InvokeRequired block"成功执行.
复制此行为非常困难,因为我们的应用程序是作为DLL提供的; 我们的客户在自己的应用程序中运行它.因此,我们无法保证可以调用这些方法的方式或方式.
我们排除了UI线程饥饿,因为观察到UI没有锁定.据推测,如果UI正在更新,则消息泵可操作并可用于从消息队列中提取消息并执行其委托.
鉴于此信息,我们可以尝试使这些调用更具防弹性吗?如前所述,我们对给定应用程序中的其他线程的控制相对较少,并且不控制调用这些方法的上下文.
还有什么可以影响委托成功传递给Control.BeginInvoke()的方式是否执行?
根据MSDN, 即使在应该存在的情况下也InvokeRequired可以返回- 即在您创建该控件/表单(或其父节点)之前访问的情况下.falseInvokeRequiredtrueInvokeRequiredHandle
基本上,您的支票不完整,这会导致您看到的结果.
你需要检查IsHandleCreated- 如果那是false你那么你有麻烦因为Invoke/ BeginInvoke将是必要的但是因为Invoke/ BeginInvoke检查创建哪个线程Handle来做他们的魔法所以不会有效地工作...
只有当IsHandleCreated是true你根据什么行动InvokeRequired返回-沿着线的东西:
if (control.IsHandleCreated)
{
if (control.InvokeRequired)
{
control.BeginInvoke(action);
}
else
{
action.Invoke();
}
}
else
{
// in this case InvokeRequired might lie - you need to make sure that this never happens!
throw new Exception ( "Somehow Handle has not yet been created on the UI thread!" );
}
Run Code Online (Sandbox Code Playgroud)
因此,以下内容对于避免此问题非常重要
始终确保Handle在第一次访问UI线程以外的线程之前已创建.
根据MSDN,您只需要control.Handle在UI线程中引用以强制它被创建 - 在您的代码中,这必须在您第一次从任何不是UI线程的线程访问该控件/表单之前发生.
有关其他可能性,请参阅@JaredPar的答案.
| 归档时间: |
|
| 查看次数: |
7690 次 |
| 最近记录: |