后台工作器不想停止
本文关键字:不想 工作 后台 | 更新日期: 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
内部调用