1

我对 Windows 窗体事件有一个奇怪的问题。确切地说,这是一个KryptonHeaderGroup的 ButtonSpec Click 事件,但它也发生在普通 vanillaSystem.Windows.Forms.Button中。

在单击事件中,用户界面被关闭(左侧有一个标签和一个取消按钮),然后从先前的用户输入构建一个昂贵的 LINQ 查询,编译然后执行。foreach 中有Application.DoEvents()实际执行查询的调用(它是对象的 LINQ,所以它很懒惰)。这使用户能够按下取消,并且在 之后DoEvents,测试取消标志并取消 foreach,并进行一些清理。到现在为止还挺好。

但是,当我在前几个结果出现后按下取消按钮时(标签显示已经有多少),整个 Click 事件处理程序重新启动!添加一些跟踪后,这似乎发生在前一个处理程序返回之前。换句话说,它发生在其中一个DoEvents调用中。当然,该按钮不再被按下。如果按钮在事件处理程序中被禁用,则不会发生这种情况。但是由于没有按下按钮,它不应该再次触发它的 Click 事件,不是吗?

我很困惑。显然,解决方法是禁用该按钮,但我想知道这里的实际问题可能是什么。DoEvents如果在处理程序完成之前调用事件处理程序,是否可以重新启动?DoEvents在事件处理程序中不推荐/不允许调用吗?但是,由于一切都是事件驱动应用程序中的事件处理程序,你永远不能调用它:)

回答此问题可能需要的其他提示:

  • LINQ 查询最初需要很长时间才能提供第一个结果,即在进行第一次DoEvents调用之前。
  • LINQ 查询在 GUI 线程中运行,因为允许用户访问其余应用程序没有意义,因为访问会干扰 GUI 和 LINQ 查询使用的底层 API。
  • 我知道我应该将 LINQ 查询加载到一个单独的应用程序域并在那里执行它,以便能够卸载它。但是典型用户只会运行几个不同的查询,并且生成的程序集被缓存(对于相同的查询字符串)。
  • 如果我启用了断点( sigh - Heisenberg,有人吗?)或者我稍后在查询期间取消,则问题不再发生。

我很感激任何可以解释这种行为的东西,即使这只是猜测:)

4

1 回答 1

3

DoEvents 将处理 GUI 消息,因此它将允许处理任何进一步的单击或消息。我建议你不要在事件处理程序中调用它,老实说我会完全避免使用它。

来自 MSDN:如果消息引发事件,调用此方法可能会导致重新输入代码。

长期:

如果这是一个长时间运行的查询,您希望查看在后台线程上运行它并禁用该按钮。这是此类活动的一般模式。

于 2009-11-23T11:23:34.440 回答