5

当应用程序执行长时间运行的任务时,您是否有一个很好的解决方案来保持“请稍候”winform“绘制”?

我已经尝试在每个步骤中使用 form.refresh() ,但是会发生一些长时间运行的查询,这意味着这不够频繁。

基本上这个SO Question但是,通过 VSTO(而不是 Python)在 Excel 中的 C# 上。

4

4 回答 4

3

正如 statichippo 提到的,我会使用 BackgroundWorker 类。其目的是简化多线程并允许工作线程在不锁定 GUI 的情况下进行耗时的处理。

这是来自MSDN的引用:

BackgroundWorker 类允许您在单独的专用线程上运行操作。下载和数据库事务等耗时的操作可能会导致您的用户界面 (UI) 在运行时似乎停止响应。当您需要响应式 UI 并且面临与此类操作相关的长时间延迟时,BackgroundWorker 类提供了一种方便的解决方案。

这是一个很好的教程,如何在 Windows 窗体中使用 BackgroundWorker 类: 使用 BackgroundWorker 类在 WinForms 中实现多线程

对于复杂的场景,在 C# 中实现多线程有更复杂的方法,但对于大多数简单的场景,BackgroundWorker 工作得很好(至少对我来说)。

以下是我从 Google 获取的关于 C# 多线程的一些链接:
MSDN Threading
Introduction to Multithreading in C#

于 2010-01-19T18:10:25.413 回答
1

另一种选择是使用异步委托在线程池线程上显示表单。

建议将线程池中的线程用于不会持续整个应用程序持续时间的较短生命周期的线程。由于这是显示一个短暂的请等待窗口,线程池是一个合理的选择。

Action 委托 (.NET 2.0+) 与 BeginInvoke() 方法一起用于在线程池线程上自动运行委托代码。

一些注意事项:

  • 对任何跨线程 GUI 调用使用 Control.BeginInvoke 很重要,例如在 ClosePleaseWait() 中关闭请等待表单。
  • 此外,m_pleaseWaitForm.ShowDialog();实际上在新线程中启动了一个新的消息循环。这就是请等待表单保持活力的原因。
  • 因为使用了线程池线程,所以该线程自动成为后台线程,如果主应用程序关闭,该线程将被终止。
  • 除了在另一个线程上运行之外,Form2 并没有什么特别之处。您可以在其上放置任何子控件,例如图片框、标签等。
  • (MethodInvoker)delegate { ... }只是在委托内联中运行代码的 .NET 2.0 方式。

下面的示例可以添加到包含 Form1:主窗体和 Form2:请等待窗体的 WinForms 项目中。

   private Form2 m_pleaseWaitForm = null;

    private void Form1_Shown(object sender, EventArgs e)
    {
        // This code could also be placed in eg. a button click event handler.

        Action<Rectangle> a = new Action<Rectangle>(ShowPleaseWait);

        a.BeginInvoke(this.Bounds, null, null);

        // Do your long running tasks

        ClosePleaseWait();
    }


    private void ShowPleaseWait(Rectangle  bounds)
    {
        // This method runs on the new thread.

        m_pleaseWaitForm = new Form2();

        m_pleaseWaitForm.TopMost = true;
        m_pleaseWaitForm.Location = new Point(bounds.Left + bounds.Width / 2 - m_pleaseWaitForm.Width / 2, bounds.Top + bounds.Height / 2 - m_pleaseWaitForm.Height / 2);

        m_pleaseWaitForm.ShowDialog();

    }

    private void ClosePleaseWait()
    {
        m_pleaseWaitForm.BeginInvoke((MethodInvoker)delegate { m_pleaseWaitForm.Close(); });
    }
于 2010-01-19T17:54:05.997 回答
0

使用 BackgroundWorker

于 2010-01-19T15:04:19.990 回答
0

这是一个很好的 C# 代码示例。

它专门用于启动屏幕,但是创建“请稍候”窗口的过程几乎相同(可能减去了一些华丽的不透明度)。

关键信息是您将需要一个单独的线程。这可能会使事情复杂化,但是本文提供了一个很好的覆盖范围/示例,说明了如何正确地做到这一点。

于 2010-01-19T15:19:42.090 回答