Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 跟踪多个后台工作人员_C#_.net_Wpf_Task Parallel Library_Backgroundworker - Fatal编程技术网

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);