我遇到Control.BeginInvoke()
的问题,每次都不会发生。它看起来效果好5次左右,然后在那之后成为50/50的成功率。
发生的事情是我将在已创建并显示的控件上调用BeginInvoke()
,并且不会立即在GUI线程上执行调用。调用线程 立即从BeginInvoke()
返回并继续其业务。在控件上执行另一个BeginInvoke()
之前,不会在GUI线程上执行该委托。然后就好像它意识到它有事可做,最后做到了。这可能超过10分钟。
代码
以下是执行不立即执行委托的BeginInvoke()
的代码:
protected void DisplayPrompt(PromptData promptData)
{
Debug.WriteLine(DateTime.Now + ": Entering DisplayPrompt: " + Thread.CurrentThread.Name);
this.CurrentPrompt = promptData;
if (this.InvokeRequired)
{
Debug.WriteLine(DateTime.Now + ": Before BeginInvoke of DisplayPrompt: " + Thread.CurrentThread.Name);
this.BeginInvoke(new Action(() => this.DisplayPrompt(promptData)));
Debug.WriteLine(DateTime.Now + ": After BeginInvoke of DisplayPrompt: " + Thread.CurrentThread.Name);
return;
}
// The rest of the method goes here
}
通过消息泵启动调用方法的原因是以下代码执行时。在我厌倦了等待执行上面的委托之后执行此代码,然后按下最终调用ClearPrompt()
的按钮。
protected void ClearPrompt()
{
Debug.WriteLine(DateTime.Now + ": Entering ClearPrompt: " + Thread.CurrentThread.Name);
this.CurrentPrompt = null;
if (this.InvokeRequired)
{
Debug.WriteLine(DateTime.Now + ": Before BeginInvoke of ClearPrompt: " + Thread.CurrentThread.Name);
this.BeginInvoke(new Action(() => this.ClearPrompt()));
Debug.WriteLine(DateTime.Now + ": After BeginInvoke of ClearPrompt: " + Thread.CurrentThread.Name);
return;
}
// The rest of the method goes here
}
最后,这是输出:
11/13/2013 1:16:49 PM: Entering DisplayPrompt: BatchStateMachine
11/13/2013 1:16:49 PM: Before BeginInvoke of DisplayPrompt: BatchStateMachine
11/13/2013 1:16:49 PM: After BeginInvoke of DisplayPrompt: BatchStateMachine
The thread 0x998 has exited with code 0 (0x0).
The thread 0x1174 has exited with code 0 (0x0).
11/13/2013 1:27:01 PM: Entering ClearPrompt: BatchStateMachine
11/13/2013 1:27:01 PM: Before BeginInvoke of ClearPrompt: BatchStateMachine
11/13/2013 1:27:01 PM: After BeginInvoke of ClearPrompt: BatchStateMachine
11/13/2013 1:27:01 PM: Entering DisplayPrompt:
11/13/2013 1:27:01 PM: Entering ClearPrompt:
这是Entering DisplayPrompt
的第二个1:27:01 PM
,这是GUI最终运行委托的地方。
问题:
所以我想问题是,什么可能导致BeginInvoke()
出现这种延迟行为,我该怎么做才能更好地调试呢?
其他说明:
UserControl
对象UserControl
对象已经存在,并且在代码运行之前已经显示了几分钟,即控件句柄应该存在。BeginInvoke()
谢谢!
答案 0 :(得分:0)
感谢Adam Maras的评论,我相信我已经找到了问题的根本原因。确实有大量的BeginInvoke()
电话正在执行,但并不是很明显。我有另一个控件从后台线程接收大量更新。不足以导致问题正常,但问题是越来越多的控件实例都在接收更新并执行BeginInvoke()
来更新GUI。
控件数量增加的原因是,当导航离开时,实例假定被销毁,并在返回到该视图时重新创建。但是,控件没有被销毁,因为它们已经从一个长期存在的类实例注册了更新事件,并且在从表单中删除控件时没有从事件中注销。这导致长期存在的类保存对所讨论的UserControl
实例的引用,并且所有实例将继续处理事件并更新GUI,即使它们甚至不再可见。
因此即使GUI在某种程度上仍然响应,它也无法满足所有传入的异步调用。我读here SendMessage
消息实际上没有像PostMessage
消息那样被添加到消息队列中,而是直接由消息泵执行,并且具有比填充的消息队列更高的优先级。 PostMessage
。因此,如果通过System.Windows.Forms.Timer
事件处理正常的按钮点击和SendMessage
事件,并且在消息队列上处理了BeginInvoke()
个调用,我就会看到这种情况会如何发生。
感谢所有有用且快速的建议!谁知道我花了多长时间寻找它!