如何停止WPF中的后台工作人员



我在WPF应用程序中使用MVVM模型。我有一个绑定到取消按钮的命令。我有一个启动按钮,可以启动一些后台工作人员。当我点击取消按钮时,我希望所有后台工作人员停止/退出。用我当前的代码,当我点击取消按钮时,后台工作人员不会停止;启动工程操作";饰面。有人能帮我解决我在这里做错了什么吗?

当前代码:

对于EngineeringViewModel.cs:

公共类EngineeringViewModel{

public EngineeringViewModel()
{
StartEngineering= new DelegateCommand(o =>
{
worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
worker.ProgressChanged += Worker_ProgressChanged;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
if (worker.IsBusy != true) worker.RunWorkerAsync();
worker.DoWork += (s, e) =>
{
StartEngineeringOperation();
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
};
},
k => true);
Cancel = new DelegateCommand(CancelEngineeringOperation);
}
private void StartEngineeringOperation()
{
startAlarmService();
startTrendQualityCheck();
}
private void CancelEngineeringOperation(object param)
{           
worker.DoWork += (s, e) =>
{
if (worker.IsBusy)
{
worker.CancelAsync();
e.Cancel = true;
return;
}

};

}
}

我试过这个:但似乎不起作用:

private void StartEngineeringOperation()
{
startAlarmService();                                                                                                      
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
startTrendQualityCheck();
}

您可能已经从te注释中了解到,您需要在操作中轮询想要支持取消的BackgroundWorker的状态。然后采取措施优雅地取消正在进行的操作。

该示例显示了如何在单击按钮时取消后台线程。第一个示例使用旧的BackgroundWorker,第二个示例使用现代且更干净的Task库。

后台工作人员

private BackgroundWorker Worker { get; set; }
private void StartWorker()
{
this.Worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};

this.Worker.DoWork += BackgroundWorker_DoWork;
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
DoCancellableWork();  
// Stop BackgroundWorker from executing
if (worker.CancellationPending)
{
e.Cancel = true;
}     
}
private void DoCancellableWork()
{      
// Check for cancellation before executing the cancellable operation and allocating resources etc..
if (this.Worker.CancellationPending)
{
return;
}
// Periodically/regularly check for the cancellation flag
for (int i = 0; i <= 10000000000; i++)
{
if (this.Worker.CancellationPending)
{
// Cancel operation gracefully e.g., do some cleanup, free resources etc.
return;
}
// Do some work
}
}
// Alternatively use a command e.g., in a view model class
private void CancelBackgroundWorker_Click(object sender, EventArgs e)
{
if (this.Worker.WorkerSupportsCancellation)
{
this.Worker.CancelAsync();
}
}

任务库

该示例使用Progress<T>以向UI线程报告从后台线程的进度。

private CancellationTokenSource CancellationTokenSource { get; set; }
private async Task StartWorker()
{
this.CancellationTokenSource = new CancellationTokenSource();
// Prepare callback to update UI from the background thread.
// The Progress<T> instance MUST be created on the UI thread
IProgress<int> progressReporter = new Progress<int>(progress => this.ProgressBar.Value = progress);
await Task.Run(
() => DoWork(progressReporter, this.CancellationTokenSource.Token), 
this.CancellationTokenSource.Token);
this.CancellationTokenSource.Dispose();
}
private void DoWork(IProgress<int> progressReporter, CancellationToken cancellationToken)
{
DoCancellableWork(progressReporter, cancellationToken);
}
private void DoCancellableWork(IProgress<int> progressReporter, CancellationToken cancellationToken)
{
// Check for cancellation before executing the operation and allocating resources etc..
if (cancellationToken.IsCancellationRequested)
{
return;
}
// Periodically/regularly check for the cancellation flag
for (int i = 0; i <= 10000000000; i++)
{
if (cancellationToken.IsCancellationRequested)
{
// Cancel operation gracefully e.g., do some cleanup, free resources etc.
return;
}
// Do some work
// Report progress
progressReporter.Report(20);
}
}
// Alternatively use a command e.g., in a view model class
private void CancelBackgroundThread_Click(object sender, EventArgs e)
{
this.CancellationtokenSource?.Cancel();
}

由于OP将要完成的任务描述为";"检查服务";,我认为完成的工作看起来像这样:

while(true){
// check service
// Post result back to UI thread
Thread.Sleep(...);
}

这不是写这样一张支票的最佳方式。在大多数使用Thread.Sleep的情况下,计时器是一个更好的选择:

var myTimer  = new System.Timers.Timer(...);
myTimer .Elapsed += OnTimedEvent;
myTimer .AutoReset = true;
myTimer .Enabled = true;
...
private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
// check service
// Post result back to UI thread
}

这使得停止/启动正在执行的任务的问题变得简单,只需更改计时器的Enabled标志即可。也可以使用定时器或同步上下文直接在UI线程上运行事件,这可能是最好的解决方案;检查服务";只需要几毫秒。

最新更新