WPF - 后台工作者不想停止

时间:2014-07-02 12:35:31

标签: c# wpf backgroundworker

我尝试更新WPF TreeView,其中每个根节点都包含多个子节点,因此我按需加载子节点""使用TreeView_Expanded事件。

当节点扩展时,将调用ViewModel中的FillFolder方法。此方法以这种方式调用主RunWorkerAsync上的BackgroundWorker

public void FillFolder(SCADAFolder selectedFolder)
{
    _bwWorker.CancelAsync();
    _bwWorker.RunWorkerAsync(selectedFolder);
}

我调用了CancelAsync方法,因为如果我扩展了一个包含数千个子节点的节点,在它结束之前我打开了另一个子节点,那么这个子节点将被填充。第一个节点打开,因为循环仍在添加项目。

这是我的BackroundWorker声明的方式:

private BackgroundWorker _bwWorker;

//Constructor
{
    _bwWorker = new BackgroundWorker();
    _bwWorker.WorkerReportsProgress = true;
    _bwWorker.WorkerSupportsCancellation = true;
    _bwWorker.DoWork += _bwWorker_DoWork;
    _bwWorker.ProgressChanged += _bwWorker_ProgressChanged;
    _bwWorker.RunWorkerCompleted += _bwWorker_RunWorkerCompleted;
    [...]
}

这就是BackgroundWorker实际做的事情:

void _bwWorker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;

    [do a query...]

    foreach (DataRowView rowView in QueryResults)
    {
        if ((worker.CancellationPending == true))
        {
            e.Cancel = true;
            selectedFolder.Items.Clear();
            break;
        }
        else
        {
            MyItem item = CreateItem();//pseudo code here

            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => selectedFolder.Items.Add(item)));
        }
    }
}

CancellationPending条件永远不会成立。

为什么?

修改

使用ThreadPool.QueueUserWorkItem(...)代替BackgroundWorker解决并使用Invoke代替BeginInvoke

1 个答案:

答案 0 :(得分:0)

您如何测试取消是否有效?您唯一的测试是继续添加项目吗?您是通过BeginInvoke添加商品的。由于这是异步的,您的工作人员可能已经完成但仍继续添加项目。

您有竞争条件,因为CancelAsync不等待工人停止。您应该将selectedFolder作为参数传递给worker,并在执行追加时使用该参数,而不是使用当时恰好选择的文件夹。

请注意,selectedFolder.Items.Clear();也需要在BeginInvoke范围内调用。