后台工作器不想停止

本文关键字:不想 工作 后台 | 更新日期: 2023-09-27 18:11:03

我正在尝试更新一个WPF TreeView,其中每个根节点包含几个子节点,所以我使用TreeView_Expanded事件"按需"加载子节点。

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

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

后台工作器不想停止

如何测试取消不工作?你唯一的测试是继续添加项目吗?您正在通过BeginInvoke添加您的项目。因为这是异步的,你的worker可能已经完成了,但是项目还在继续添加。

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

注意selectedFolder.Items.Clear();也需要从BeginInvoke内部调用