概述
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();
}
}
在这里,我们为了在UI线程上运行委托,显式创建一个名为“hiddenControl”的控件。我们从不调用endInvoke,因为对于Control.BeginInvoke来说,这似乎是不必要的,而且我们也从来不需要返回值,因为我们的方法只是操作UI。
尽管非常冗长,该模式似乎是比较 被广泛 接受的解决方案。然而,有证据表明,即使在所有情况下,这种模式也可能效果不佳。
观察
我不排除应用程序错误并将其归咎于WinForms。毕竟,select probably isn't broken。然而,我无法解释为什么委托可能似乎根本没有运行。在我们的情况下,我们有时会观察到在某些线程场景中,“uiDelegate的开始”日志消息从未执行,即使“InvokeReqiured块的开始”和“InvokeRequired块的结束”成功执行。
由于我们的应用程序作为DLL交付,因此很难复制此行为。我们的客户在自己的应用程序中运行它。因此,我们不能保证这些方法可能以何种方式或在哪个线程中被调用。
我们排除了UI线程饥饿现象,因为观察到UI没有锁定。假设如果正在更新UI,则消息泵正在操作并可用于从消息队列中拉取消息并执行其委托。
总结:
鉴于这些信息,是否有任何可以尝试使这些调用更加牢固的方法?如先前提到的,我们对给定应用程序中的其他线程相对较少控制,并且不控制调用这些方法的上下文。
什么因素会影响委托成功传递给Control.BeginInvoke()并执行的情况?