C# 跟踪多个后台工作人员
我有一个C# 跟踪多个后台工作人员,c#,.net,wpf,task-parallel-library,backgroundworker,C#,.net,Wpf,Task Parallel Library,Backgroundworker,我有一个WPF应用程序,我正在使用BackgroundWorker组件从后端检索一些数据并将其显示在UI中 BackgroundWorker具有WorkerReportsProgress=true,因此可以定期更新UI。BackgroundWorker还具有WorkerSupportsCancellation=true,因此用户可以取消它。一切都很好 我在尝试实现第三个也是更复杂的行为时遇到困难。基本上,用户需要有灵活性,可以随时启动新的BackgroundWorker任务,包括当前正在执行的任
WPF
应用程序,我正在使用BackgroundWorker
组件从后端检索一些数据并将其显示在UI中
BackgroundWorker
具有WorkerReportsProgress=true
,因此可以定期更新UI。BackgroundWorker
还具有WorkerSupportsCancellation=true
,因此用户可以取消它。一切都很好
我在尝试实现第三个也是更复杂的行为时遇到困难。基本上,用户需要有灵活性,可以随时启动新的BackgroundWorker
任务,包括当前正在执行的任务。如果当前正在执行一项任务并启动了一项新任务,则需要将旧任务标记为已中止
<代码>中止任务不同于取消
,因为中止
不允许进行任何进一步的UI更新。应该“悄悄地取消”
我将BackgroundWorker
包装在AsyncTask
类中,并添加了isborted
位。根据ProgressChanged
和RunWorkerCompleted
中的isborted
位进行检查,可防止进一步的UI更新。太好了
但是,这种方法会出现故障,因为当启动新任务时,CurrentTask
将替换为AsyncTask
的新实例。因此,很难跟踪当前任务
如前所述,在TODO:
中,我几乎想在中止后等待当前任务
完成,然后再开始新任务。但我知道这将提供糟糕的用户体验,因为UI线程将被阻塞,直到旧任务完成
有没有更好的方法来跟踪多个异步任务
以确保新任务可以按需启动,而旧任务可以在没有进一步UI更新的情况下正确中止?似乎没有跟踪当前任务的好方法。。。第三方物流是否提供了更好的方式来处理我的需求
下面是我的Window类中值得注意的片段:
private AsyncTask CurrentTask { get; set; }
private class AsyncTask
{
private static int Ids { get; set; }
public AsyncTask()
{
Ids = Ids + 1;
this.Id = Ids;
this.BackgroundWorker = new BackgroundWorker();
this.BackgroundWorker.WorkerReportsProgress = true;
this.BackgroundWorker.WorkerSupportsCancellation = true;
}
public int Id { get; private set; }
public BackgroundWorker BackgroundWorker { get; private set; }
public bool IsAborted { get; set; }
}
void StartNewTask()
{
if (this.CurrentTask != null && this.CurrentTask.BackgroundWorker.IsBusy)
{
AbortTask();
//TODO: should we wait for CurrentTask to finish up? this will block the UI?
}
var asyncTask = new AsyncTask();
asyncTask.BackgroundWorker.DoWork += backgroundWorker_DoWork;
asyncTask.BackgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
asyncTask.BackgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
AppendText("Starting New Task: " + asyncTask.Id);
this.CurrentTask = asyncTask;
asyncTask.BackgroundWorker.RunWorkerAsync();
}
void AbortTask()
{
if (this.CurrentTask != null && this.CurrentTask.BackgroundWorker.IsBusy)
{
AppendText("Aborting Task " + this.CurrentTask.Id + "...");
this.CurrentTask.IsAborted = true;
this.CurrentTask.BackgroundWorker.CancelAsync();
}
}
void CancelTask()
{
if (this.CurrentTask != null && this.CurrentTask.BackgroundWorker.IsBusy)
{
AppendText("Cancelling Task " + this.CurrentTask.Id + "...");
this.CurrentTask.BackgroundWorker.CancelAsync();
}
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
var backgroundWorker = (BackgroundWorker)sender;
for (var i = 0; i < 10; i++)
{
//check before making call...
if (backgroundWorker.CancellationPending)
{
e.Cancel = true;
return;
}
//simulate a call to remote service...
Thread.Sleep(TimeSpan.FromSeconds(10.0));
//check before reporting any progress...
if (backgroundWorker.CancellationPending)
{
e.Cancel = true;
return;
}
backgroundWorker.ReportProgress(0);
}
}
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (this.CurrentTask.IsAborted)
return;
AppendText("[" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "] " + "Progress on Task: " + this.CurrentTask.Id + "...");
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (this.CurrentTask.IsAborted)
return;
if (e.Cancelled)
{
AppendText("Cancelled Task: " + this.CurrentTask.Id);
}
else if (e.Error != null)
{
AppendText("Error Task: " + this.CurrentTask.Id);
}
else
{
AppendText("Completed Task: " + this.CurrentTask.Id);
}
//cleanup...
this.CurrentTask.BackgroundWorker.DoWork -= backgroundWorker_DoWork;
this.CurrentTask.BackgroundWorker.ProgressChanged -= backgroundWorker_ProgressChanged;
this.CurrentTask.BackgroundWorker.RunWorkerCompleted -= backgroundWorker_RunWorkerCompleted;
this.CurrentTask= null;
}
private AsyncTask CurrentTask{get;set;}
私有类异步任务
{
私有静态int-id{get;set;}
公共异步任务()
{
Ids=Ids+1;
Id=Id;
this.BackgroundWorker=新的BackgroundWorker();
this.BackgroundWorker.WorkerReportsProgress=true;
this.BackgroundWorker.workerSupportsScanCellation=true;
}
public int Id{get;private set;}
公共后台工作程序后台工作程序{get;private set;}
公共布尔值为{get;set;}
}
void StartNewTask()
{
if(this.CurrentTask!=null&&this.CurrentTask.BackgroundWorker.IsBusy)
{
AbortTask();
//TODO:我们是否应该等待CurrentTask完成?这将阻止UI?
}
var asyncTask=new asyncTask();
asyncTask.BackgroundWorker.DoWork+=BackgroundWorker\u DoWork;
asyncTask.BackgroundWorker.ProgressChanged+=BackgroundWorker\u ProgressChanged;
asyncTask.BackgroundWorker.RunWorkerCompleted+=BackgroundWorker\u RunWorkerCompleted;
AppendText(“启动新任务:+asyncTask.Id”);
this.CurrentTask=asyncTask;
asyncTask.BackgroundWorker.RunWorkerAsync();
}
void AbortTask()
{
if(this.CurrentTask!=null&&this.CurrentTask.BackgroundWorker.IsBusy)
{
AppendText(“正在中止任务”+this.CurrentTask.Id+”);
this.CurrentTask.IsOrted=true;
this.CurrentTask.BackgroundWorker.CancelAsync();
}
}
作废取消任务()
{
if(this.CurrentTask!=null&&this.CurrentTask.BackgroundWorker.IsBusy)
{
附录文本(“取消任务”+this.CurrentTask.Id+”);
this.CurrentTask.BackgroundWorker.CancelAsync();
}
}
无效backgroundWorker_DoWork(对象发送方,DoWorkEventArgs e)
{
var backgroundWorker=(backgroundWorker)发送方;
对于(变量i=0;i<10;i++)
{
//打电话前先检查一下。。。
if(backgroundWorker.CancellationPending)
{
e、 取消=真;
返回;
}
//模拟对远程服务的调用。。。
睡眠(时间跨度从秒(10.0));
//在报告任何进展之前检查。。。
if(backgroundWorker.CancellationPending)
{
e、 取消=真;
返回;
}
backgroundWorker.ReportProgress(0);
}
}
void backgroundWorker\u ProgressChanged(对象发送方,ProgressChangedEventArgs e)
{
if(this.CurrentTask.IsOrted)
返回;
AppendText(“[”+DateTime.Now.ToString(“MM/dd/yyyy HH:MM:ss”)+“]”+“任务进度:”+this.CurrentTask.Id+”);
}
void backgroundWorker\u RunWorkerCompleted(对象发送方,runworkercompletedeventarge)
{
if(this.CurrentTask.IsOrted)
返回;
如果(如已取消)
{
AppendText(“已取消的任务:+this.CurrentTask.Id”);
}
否则如果(例如错误!=null)
{
AppendText(“错误任务:+this.CurrentTask.Id”);
}
其他的
{
AppendText(“已完成任务:+this.CurrentTask.Id”);
}
//清理。。。
this.CurrentTask.BackgroundWorker.DoWork-=BackgroundWorker\u DoWork;
this.CurrentTask.BackgroundWorker.ProgressChanged-=BackgroundWorker\u ProgressChanged;
this.CurrentTask.BackgroundWorker.RunWorkerCompleted-=BackgroundWorker\u RunWorkerCompleted;
this.CurrentTask=null;
}
据我所知,您不希望实际中止线程,您只希望它继续以静默方式工作(即不更新UI)?一种方法是保留一个BackgroundWorker列表,如果要“中止”,则删除其事件处理程序
List allBGWorkers=new List();
//用户创建一个新的bg工作进程。
BackgroundWorker newgWorker=新的BackgroundWorker();
//.... 填写属性
//在将新的bg工作程序添加到列表之前,请遍历该列表
//并确保从现有事件处理程序中删除事件处理程序
List<BackgroundWorker> allBGWorkers = new List<BackgroundWorker>();
//user creates a new bg worker.
BackgroundWorker newBGWorker = new BackgroundWorker();
//.... fill out properties
//before adding the new bg worker to the list, iterate through the list
//and ensure that the event handlers are removed from the existing ones
foreach(var bg in allBGWorkers)
{
bg.ProgressChanged -= backgroundWorker_ProgressChanged;
bg.RunWorkerCompleted -= backgroundWorker_RunWorkerCompleted;
}
//add the latest bg worker you created
allBGWorkers.Add(newBGWorker);