1

在一些代码中看到了这一点,但对我来说没有意义,所以我想知道这是否是利用背景工作者的正确方法?

它在 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

4 回答 4

2

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

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

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

当然,长时间运行的 lop 必须在事件内部运行,而不是在与调用相同的代码块中,如您的代码示例中那样。DoWorkRunWorkerAsync

相反,如果我们只是在谈论大量现成的项目,并且AddRange由于数量的原因,调用简单地需要很多时间,则不能从后台线程调用它,因为只能从以下位置访问 winforms 控件用户界面线程。

于 2012-09-11T15:14:21.427 回答
2

我会为此使用Task Parralell Library。一个很好的教程是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 线程,该委托在前面的任务完成(成功或其他方式)时触发。

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

我希望这有帮助。

于 2012-09-11T15:29:11.463 回答
1

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

BackgroundWorker 将工作从 UI 线程中分离出来,并具有提供轻松访问更新进度的方法。

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

于 2012-09-11T15:14:07.563 回答
1

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

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

于 2012-09-11T15:14:22.643 回答