【问题标题】:Background Worker doubts背景工作者的疑惑
【发布时间】:2014-01-23 16:34:11
【问题描述】:

我正在开发一个简单的 winforms C# 应用程序。我想使用后台工作人员在顶部显示加载表单,而另一个后台工作人员正在咨询我的 WCF 服务器。

我的 WinForms 应用程序是这样工作的: 我有一个 MainForm 和很多用户控件。当我启动应用程序时,我将 LoginUserControl 添加到 MainForm 控件。当我单击 LoginUserControl 中的“登录按钮”时,我想同时显示加载表单并咨询服务器。稍后,我需要向 Loading Background Worker 发送一个信号,表明 Server Consult Background Worker 已完成。

我的问题是,我应该为每个需要加载面板的 UserControl 实现 2 个后台工作程序吗?以及如何实现Background Worker之间的通信?

【问题讨论】:

  • 这可能会有所帮助 - 类似的事情(闪屏)stackoverflow.com/questions/7955663/…
  • 如果可能,在处理 I/O 绑定操作时使用asyncawait 而不是BackgroundWorker
  • 为什么有两个BackgroundWorker?显示最上面的表单,调用一个后台工作者,最后完成的事件移除表单。

标签: c# .net winforms wcf backgroundworker


【解决方案1】:

稍后,我需要向 Loading Background Worker 发送一个信号,表明 Server Consult Background Worker 已完成。

不,你不需要。

后台工作人员正是它所说的:在后台执行任务的“工作人员”。您的任务是与您拥有的 WCF 服务进行通信的方法。当工作完成(或抛出异常)时,worker 将结束。所以事件的先后顺序如下:

  • 启动工作器(如果您的表单是模态的,则必须首先启动)
  • 显示表格
  • 监听worker RunWorkerCompleted 事件以隐藏表单

事实上,我已经创建了一个执行类似操作的表单,只是我不与服务器通信(实际上并不重要)并且我显示了一个简单的进度条。

public partial class FastForwardForm : Form
{
    private Exception asyncError;

    public event DoWorkEventHandler DoWork
    {
        add { worker.DoWork += value; }
        remove { worker.DoWork -= value; }
    }

    public FastForwardForm()
    {
        InitializeComponent();
    }

    public Exception AsyncError
    {
        get { return asyncError; }
    }

    private void FastForwardForm_Shown(object sender, EventArgs e)
    {
        worker.RunWorkerAsync();
    }

    private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar.Value = e.ProgressPercentage;
        statusLabel.Text = e.UserState.ToString();
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null) asyncError = e.Error;
        HideProgressForm();
        worker.Dispose();
    }

    private void HideProgressForm()
    {
        //not actually needed, the callback runs on the UI thread.
        if (InvokeRequired)
        {
            Invoke((Action)HideProgressForm);
            return;
        }
        Close();
    }
}

请注意以下几点:

  • workerControl 的子类,所以我通过表单编辑器添加了它。这也意味着它的回调在 UI 线程上执行,您不需要需要我添加的 if (InvokeRequired) 部分。不要问我为什么会出现,重构后我错过了:)
  • 表单为您完成了一些繁琐的工作:一旦显示就启动工作程序。存储进程的异常。公开DoWork,以便您可以从表单外的任何位置添加后台工作。
  • 代码并不完美:如果需要重用表单,则必须删除 worker.Dispose(); 并将其添加到表单 Dispose() 方法中。

现在,如果您需要在表单中显示一些“等待”动画,则不需要其他工作人员。您需要一个 Timer 控件来刷新动画,但这是另一回事。

【讨论】:

    【解决方案2】:

    首先,从BackgroundWorker 开始Form 是个坏主意。这会干扰 Windows 窗体具有的单个 UI 线程。

    您最好从 UI 线程中打开 Form 并从 BackgroundWorker 中调用 Invoke 以关闭表单。

    form.Invoke((MethodInvoker)delegate()
    {
        busyForm.Close();
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-02
      • 1970-01-01
      • 2017-02-16
      • 2013-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多