一个简单的search for DoEvents 会带来很多结果,这些结果基本上可以导致:



通常引用的原因有:

  • 重新进入问题
  • 性能不佳
  • 可用性问题(例如,在禁用的窗口上拖放)

  • 但是像TrackPopupMenu一样,一些著名的Win32函数(例如DoDragDropDoEvents)执行自己的消息处理以保持UI响应。
    但是,这些似乎都没有遇到这些问题(性能,可重入性等)。

    他们是如何做到的呢?他们如何避免DoEvents引用的问题? (或者他们?)

    最佳答案

    DoEvents()很危险。但是我敢打赌,您每天都会做很多危险的事情。就在昨天,我引爆了一些爆炸装置( future 的读者:请注意相对于某个美国假期的原始发帖日期)。小心谨慎,有时我们可以解决这些危险。当然,这意味着了解并了解危险所在:

  • 重新输入问题。 这里实际上存在两种危险:
  • 这里的部分问题与调用堆栈有关。如果您在本身处理使用DoEvents()的消息的循环中调用.DoEvents(),依此类推,您将获得一个非常深的调用堆栈。过度使用DoEvents()并意外填充您的调用堆栈很容易,从而导致StackOverflow异常。如果仅在一两个地方使用.DoEvents(),则可能还可以。如果它是您长期运行的过程中可以使用的第一个工具,那么您很容易在这里遇到麻烦。甚至在错误的地方使用一次,都可能使用户强制执行stackoverflow异常(有时只需按住Enter键),这可能是安全问题。
  • 有时可以在调用堆栈中找到两次相同的方法。如果您没有牢记这一点构建方法(提示:您可能没有),那么可能会发生不好的事情。如果传递给该方法的所有内容都是值类型,并且不依赖于该方法外部的内容,则可能会很好。但是否则,您需要仔细考虑如果在调用.DoEvents()时将控制权返回给您之前再次运行整个方法会发生什么情况。您可能无法修改方法外的哪些参数或资源?您的方法是否更改任何对象,而堆栈上的两个实例可能都作用于同一对象?
  • 性能问题。 DoEvents()可以给人以多线程的错觉,但这并不是真正的多线程。这至少具有三个实际危险:
  • 调用DoEvents()时,您是将对现有线程的控制权交还给消息泵。消息泵可能又将控制权交给了其他东西,而其他东西可能需要一段时间。结果是,与原始线程永远不会产生控制权的线程相比,原始操作可能需要更长的时间才能完成,这肯定比所需时间更长。
  • 工作重复。由于可以发现自己两次运行相同的方法,并且我们已经知道此方法是昂贵的/长期运行的(或者您一开始就不需要DoEvents()),即使您考虑了所有提到的外部依赖项因此,没有不利的副作用,您仍然可能会重复很多工作。
  • 另一个问题是第一个问题的极端版本​​:可能造成死锁。如果程序中的其他内容取决于您的过程完成情况,并且将阻塞直到执行完毕,并且该事件被DoEvents()的消息泵调用,则您的应用程序将被卡住并且变得无响应。这听起来有些牵强,但实际上,意外地做到这一点非常容易,而且崩溃很难在以后找到和调试。这是您在自己的计算机上可能遇到的某些挂起的应用程序情况的根源。
  • 可用性问题。 这些是由于未适当考虑其他危险而导致的副作用。只要您在其他地方有适当的眼光,这里就没有新事物。

  • 如果可以使用,则可以确定已考虑所有这些情况,然后继续。但是,实际上,如果您首先寻求解决UI响应性/更新问题的方法是DoEvents(),则可能无法正确解决所有这些问题。如果不是您首先看到的地方,那么还有足够多的其他选择让我怀疑您是如何考虑DoEvents()的。如今,DoEvents()的存在主要是为了与在其他可用的可靠选项之前出现的旧代码兼容,并且对于尚未获得足够经验来接触其他选项的新程序员来说,这是一个拐杖。

    现实是,至少在.Net世界中,大多数时候, BackgroundWorker 组件几乎一样容易,至少一次或两次完成后,它就会以安全的方式完成工作。最近,异​​步/等待模式或使用 Task 可以更加有效和安全,而无需自己研究成熟的多线程代码。

    关于windows - 如何在不使用 “evil”的情况下使用DoEvents()?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11352301/

    10-12 12:49