这是使用后台工作者的正确方法吗?

时间:2012-09-11 15:06:27

标签: c# winforms

在一些代码中看到这个,但对我没有意义,所以我想知道即使这是一个正确的方式来利用后视工作者?

在Form_Load事件中使用它:

    BackgroundWorker asyncWorker = new BackgroundWorker();
    asyncWorker.DoWork += new DoWorkEventHandler(AsynchDoWork);
    asyncWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(AsynchCompleted);
    asyncWorker.RunWorkerAsync();

   // a for each loop that can take some time to populate a combobx on the form

此外,是否有更好的选择来实现同一目标?背景工作者除外?

4 个答案:

答案 0 :(得分:2)

如果我理解正确,你实际上要问的是你是否应该从后台线程或UI线程填充Combobox中的值。

如果填充Combobox需要很长时间的原因是因为实际检索项目需要很长时间 - 例如,如果要从数据库中检索它们,那么您可能应该这样做在BackgroundWorker中工作,然后只将检索到的项目添加到Combobox事件的RunWorkerCompleted

RunWorkerCompleted事件在仍然从后台线程运行时会自动调用Invoke以便对UI元素进行所有访问,因此更新UI元素没有问题。

当然,长时间运行的lop必须在DoWork事件内部,并且在与{{{{}}调用相同的代码块中 1}},如代码示例中所示。

相反,如果我们只是在谈论大量现成的商品,而RunWorkerAsync的电话会因为数量而花费很多时间,您可以从后台线程调用此方法,因为只能从UI线程访问winforms控件。

答案 1 :(得分:2)

我会使用Task Parralell库来实现此目的。一个很好的教程是Task Parallel Library: 1 of n。要根据某些后台任务的结果更新组合框,您可以执行类似这样的操作

// Get UI scheduler. Use this to update ui thread in continuation.
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();

// You can use TPL like this...
List<object> objList = new List<object>();
Task<object[]> task = Task.Factory.StartNew<object[]>(() =>
    {
        // Pull all your data into some object.
        object[] objArr = new object[] { "Some", "Stuff", "..." };
        return objArr;
    }, TaskCreationOptions.PreferFairness);

// Continuation firs after the antecedent task is completed.
task.ContinueWith(ant =>
    {
        // Get returned data set.
        object[] resultSet = (task.Result as object[]);

        // Check task status.
        switch (task.Status)
        {
            // Handle any exceptions to prevent UnobservedTaskException.             
            case TaskStatus.RanToCompletion:
                if (task.Result != null)
                {
                    // Update UI comboBox.
                }
                break;
            default:
                break;
        }
    }, CancellationToken.None, TaskContinuationOptions.None, uiScheduler);

这里uiScheduler允许你更新继承委托中的ui线程,当先行任务完成时(成功或以其他方式),它会触发。

在这种情况下,continuation还充当异常处理程序,以捕获它们可能从后台线程抛出的任何AggregateExceptions

我希望这会有所帮助。

答案 2 :(得分:1)

我不确定范围,我会将BackgroundWorker创建为该类的成员。

BackgroundWorker将工作从UI线程中删除,并提供方便的访问更新进度的方法。

至于替代方案,这取决于你的目标究竟是什么。如果它是一个不更新UI的小任务,那么System.Threading.ThreadPool是一个选项。

答案 3 :(得分:1)

回答这个问题“另外,除了背景工作者之外,是否有更好的选择来实现相同的目标?”。

没有。这是处理winforms长时间运行阻塞任务的最简单方法。还有其他方法(BeginInvoke),但只使用后台工作程序要容易得多。