0

这是从另一个表单更新对话框的后续问题(可以在此处找到代码和屏幕截图)

为了解决我的 GUI 挂起问题,我收到了 2 条建议:

  • 使用Application.DoEvents()

  • 用一个BackgroundWorker

DoEvents() 方法有效,但有人指出我不应该使用它。事实上,我注意到 GUI 更新正确,但在短时间内没有响应。

这就是我想使用 BackgroundWorker 并阅读它的原因。

不过,我不明白我将如何实现它,以便它可以用于分别更新示例代码中的 4 个标签。当程序成功完成一项工作时,我想显示进度(并更新 4 个对话框标签)。BackgroundWorker 虽然只有 1 个DoWork()。我曾尝试使用 的e.ArgumentDoWorkEventArgs区分不同的更新方法,但该尝试失败了。

public partial class BackgroundWorkerImportStatusDialog : Form
{
    private BackgroundWorker dialogWorker = new BackgroundWorker();

    private string path;
    private string clientName;

    public BackgroundWorkerImportStatusDialog()
    {
        InitializeComponent();
    }

    public void updateFileStatus(string path)
    {
        this.path = path;

        dialogWorker = new BackgroundWorker();
        dialogWorker.DoWork += new DoWorkEventHandler(updateLabels);
        dialogWorker.RunWorkerAsync(UpdateComponent.FileStatus);

    }

    public void updatePrintStatus()
    {
        dialogWorker = new BackgroundWorker();
        dialogWorker.DoWork += new DoWorkEventHandler(updateLabels);
        dialogWorker.RunWorkerAsync(UpdateComponent.PrintStatus);
    }

    public void updateImportStatus(string clientName)
    {
        this.clientName = clientName;

        dialogWorker = new BackgroundWorker();
        dialogWorker.DoWork += new DoWorkEventHandler(updateLabels);
        dialogWorker.RunWorkerAsync(UpdateComponent.ImportStatus);
    }

    public void updateArchiveStatus()
    {
        dialogWorker = new BackgroundWorker();
        dialogWorker.DoWork += new DoWorkEventHandler(updateLabels);
        dialogWorker.RunWorkerAsync(UpdateComponent.ArchiveStatus);
    }

    private void updateLabels(object sender, DoWorkEventArgs e)
    {
        MessageBox.Show(e.Argument.ToString());
        if ((UpdateComponent) e.Argument == UpdateComponent.FileStatus)
        {
            t_filename.Text = path;
        }
        if ((UpdateComponent) e.Argument == UpdateComponent.PrintStatus)
        {
            t_printed.Text = "sent to printer";
        }
        if ((UpdateComponent) e.Argument == UpdateComponent.ImportStatus)
        {
            t_client.Text = clientName;
        }
        if ((UpdateComponent) e.Argument == UpdateComponent.ArchiveStatus)
        {
            t_archived.Text = "archived";
        }
    }

    public enum UpdateComponent { FileStatus, PrintStatus, ImportStatus, ArchiveStatus}

而且我无法想象为这个非常简单的对话框设置 4 个 BackgroundWorker 是解决方案。

4

1 回答 1

1

据我了解您的问题,您希望让您的对话框表单通知用户您的应用程序运行的 4 个不同方面:

  • 打印状态
  • 文件状态
  • 进口状况
  • 归档状态

后台工作人员可用于定期检查每一项。检查每个操作的状态后,您可以将进度条提高 25%(并使用适当的信息更新您的 UI)。

您也可以尝试异步编程 - 即只需启动操作,然后让您的应用程序继续运行。操作完成后,您的应用程序将收到通知,并且可以更新表单上的信息。根据您使用的 .NET 框架,您可以使用asyncawait(自 .NET 4.5 / C# 5 - async & await 在 MSDN 上可用)或异步编程的经典方法


编辑:

我不确定 BackgroundWorker 是这种情况下的最佳解决方案。我可以想象有类似的东西:

  1. BackhgroundWorker 只检查一次 - 即检查一次打印状态、一次文件状态、一次导入状态、一次存档器状态。这可能听起来很傻,但它可能是用户行为驱动程序 - 即当用户单击或以任何其他方式调用此机制时显式启动。ProgressBar 可以放在应用程序的状态栏上,以便用户知道“应用程序实际上正在做某事”。

  2. 以前的方法可以稍微改进一下——你实际上从来没有在 BackgroundWorker 中完成你的工作——而是在你的 main 方法中你只有一个无限循环。这将允许您定期检查。在这种方法中,增加进度没有意义。

第二种方法的示例:

private void bg_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    for (int i = 1; i <= 10; i++)
    {
        if (worker.CancellationPending == true)
        {
            e.Cancel = true;
            break;
        }
        else
        {
            CheckPrintingStatus();
            CheckFileStatus();
            CheckImportStatus();
            CheckArchiverStatus();
            System.Threading.Thread.Sleep(5000); // sleep for 5 seconds
        }
    }
}

这个解决方案(第二种方法)是否比显式创建线程更好,这是一个问题。您可以考虑创建 4 个不同的线程,以便每个线程都可以检查其他内容。这在操作系统上会有点重,但另一方面,您可以为每个操作设置不同的睡眠时间。

如果您选择裸线程 - 您可能希望使用ThreadPool而不是显式创建线程。

于 2012-09-02T13:04:22.837 回答