【问题标题】:C# Equivalent of VB 6 DoEventsVB 6 DoEvents 的 C# 等效项
【发布时间】:2023-03-07 19:15:01
【问题描述】:

VB6 有一个 DoEvents() 方法,您可以调用该方法将控制权返回给操作系统并在单线程环境中模拟多线程行为。

什么是 .NET 框架等效于 VB 6 DoEvents()?

【问题讨论】:

  • 我认为您正在考虑 Doevents。 Yield 是一种用于枚举处理的 .NET 方法。 .NET 中的等价物是 Application.DoEvents() (无论使用什么语言)
  • Application.DoEvents() == DoEvents?
  • @Marlon:我明白了。实际上,我记得每隔几年问一次这个问题。我不记得我上次问是什么时候了。你可能是对的,这可能是答案,但我的记忆让我失望。我还认为我在 System.Diagnostics.Process 类的一种方法中找到了替代品,但我记不清了。
  • @Marlon:我检查了文档。该 Application 类位于 System.Windows.Forms 程序集中。我假设它是应用程序(MFC WinApp 类或控制主窗口的创建、注册它以及将消息分派到 WndProc 的逻辑结构/类)。我正在使用控制台应用程序。我可以引用 System.Windows.Forms dll,但这将是一个巨大的内存负担,我仍然不确定它是否可以工作。我想我会调查 Process 类的成员。
  • 在人们再次尝试关闭它之前要明确一点 DoEvents() !== yield。谢谢。

标签: c# .net vb.net vb6


【解决方案1】:

您可以使用Application.DoEvents()。为什么不使用 Threading 类或干脆使用 Background Workers?如果您在.net 环境中进行操作,请不要使用DoEvents。将其保留在 VB6 上。

【讨论】:

  • 你完全错过了线程的重点。将工作放在后台线程上是为了将 UI 工作与后台工作分开。这不是问题。问题是如何“将控制权返回给操作系统并在该单线程环境中模拟多线程行为”。 UI 可以锁定屏幕,但不能将 UI 工作放在后台线程上,否则会出现跨线程异常。答案是在繁重的工作循环中使用 await Dispatcher.Yield()。
  • 因为它是专门要求的,不那么复杂并且可以满足需要。
【解决方案2】:

Application.DoEvents()(WinForms 的一部分)

【讨论】:

  • WPF 怎么样?我讨厌 WinForms
  • @ColeJohnson 旧的 Application.DoEvents() 方法已在 WPF 中被弃用,支持使用 DispatcherBackground Worker Thread 来执行您所描述的处理。有关如何使用这两个对象的文章,请参阅链接。
  • 一般来说,无论如何我都不推荐使用 DoEvents。它可以停止 GUI。 Application.DoEvents 的谷歌问题
  • Application.DoEvents()的存在是为了VB6程序的移植。新开发的程序不应使用这种方法。
  • Dispatcher.Yield 比 Application.DoEvents 好很多
【解决方案3】:

下面是一个通用的DoEvents类型方法

using System;
using System.Windows.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Permissions;

namespace Utilites
{
/// <summary>
/// Emulates the VB6 DoEvents to refresh a window during long running events
/// </summary>
public class ScreenEvents
{
    [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
    public static void DoEvents()
    {
        DispatcherFrame frame = new DispatcherFrame();
        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
            new DispatcherOperationCallback(ExitFrame), frame);
        Dispatcher.PushFrame(frame);
    }

    public static object ExitFrame(object f)
    {
        ((DispatcherFrame)f).Continue = false;

        return null;
    }
}
}

它不需要知道应用程序。

【讨论】:

    【解决方案4】:

    如果您在代码中调用 Application.DoEvents(),您的应用程序可以处理其他事件。例如,如果您有一个将数据添加到 ListBox 并将 DoEvents 添加到您的代码的表单,则当另一个窗口被拖到它上面时,您的表单会重新绘制。如果从代码中删除 DoEvents,则在按钮的单击事件处理程序完成执行之前,您的表单不会重新绘制。有关消息传递的详细信息,请参阅 Windows 窗体中的用户输入。

    与 Visual Basic 6.0 不同,DoEvents 方法不调用 Thread.Sleep 方法。

    【讨论】:

      【解决方案5】:

      您不应该使用 Application.DoEvents()。它将有重入问题。您应该在循环内调用:

      await System.Windows.Threading.Dispatcher.Yield()
      

      它会做同样的事情。不过,您需要将其放入异步方法中。这具有将方法标记为异步调用方法的额外优势。使用 Async() 为调用 await Dispatcher.Yield 的方法添加后缀是很好的。该方法自然不是异步的(即它确实具有 CPU 绑定工作),但出于所有意图和目的,该方法变为异步,因为它不会锁定调用线程。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-16
        • 1970-01-01
        • 2010-10-24
        • 2013-07-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多