gpt4 book ai didi

c# - Control.BeginInvoke 不执行委托(delegate)的原因?

转载 作者:行者123 更新时间:2023-11-30 19:02:48 25 4
gpt4 key购买 nike

概览

是否有 Control.BeginInvoke() 不执行传递给它的委托(delegate)的解释?

代码示例

我们在 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();
}
}

在这里,我们明确创建了一个控件“hiddenControl”,用于在 UI 线程上运行委托(delegate)。我们从不调用 endInvoke 因为它显然是 not required对于 Control.BeginInvoke,我们永远不需要返回值,因为无论如何我们的方法只是操纵 UI。

虽然非常冗长,但这个模式似乎是一个 relatively well accepted solution .然而,有一些evidence即使是这种模式也可能无法在所有情况下都适用。

观察

我不排除应用程序错误并责怪 WinForms。毕竟,select probably isn't broken .然而,我无法解释为什么代表似乎根本不参选。

在我们的案例中,我们有时会观察到“Start of uiDelegate”日志消息在某些线程场景中永远不会执行,即使“Start of InvokeReqiured block”和“End of InvokeRequired block”成功执行也是如此。

复制这种行为非常困难,因为我们的应用程序是作为 DLL 交付的;我们的客户在他们自己的应用程序中运行它。因此,我们无法保证如何或在哪个线程中调用这些方法。

我们排除了 UI 线程饥饿,因为观察到 UI 没有锁定。据推测,如果正在更新 UI,则消息泵可以运行并可用于从消息队列中提取消息并执行它们的委托(delegate)。

总结

根据这些信息,我们可以尝试做些什么来使这些调用更加可靠?如前所述,我们对给定应用程序中的其他线程的控制相对较少,并且不控制调用这些方法的上下文。

还有什么可以影响委托(delegate)如何成功传递给 Control.BeginInvoke() 执行或不执行?

最佳答案

根据 MSDN即使在 InvokeRequired 应该是 true 的情况下,InvokeRequired 也可以返回 false - 即在您访问 的情况下>InvokeRequired 在创建该控件/窗体(或其父级)的 Handle 之前。

基本上您的检查不完整导致您看到的结果。

你需要检查IsHandleCreated - 如果那是 false 那么你就有麻烦了,因为 Invoke/BeginInvoke 是必需的,但由于 Invoke 而无法正常工作/BeginInvoke 检查哪个线程创建了 Handle 来发挥它们的魔力...

只有当 IsHandleCreatedtrue 时,您才会根据 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!" );
}

因此,以下内容对于避免此问题很重要

始终确保在 UI 线程以外的线程上首次访问之前已经创建了 Handle

根据 MSDN您只需要在 UI 线程中引用 control.Handle 以强制创建它 - 在您的代码中,这必须在您第一次从非 UI 的任何线程访问该控件/表单之前发生线程。

对于其他可能性,请参阅@JaredPar 的回答。

关于c# - Control.BeginInvoke 不执行委托(delegate)的原因?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8978573/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com