gpt4 book ai didi

c# - 跟踪多个 BackgroundWorker

转载 作者:太空狗 更新时间:2023-10-29 21:09:25 27 4
gpt4 key购买 nike

我有一个 WPF 应用程序,我正在使用 BackgroundWorker 组件从后端检索一些数据并将其显示在 UI 中。

BackgroundWorkerWorkerReportsProgress = true 以便 UI 可以定期更新。 BackgroundWorker 也有 WorkerSupportsCancellation = true 以便它可以被用户取消。一切都很好!

我在尝试实现第三个更复杂的行为时遇到了问题。基本上,用户需要能够灵活地随时启动新的 BackgroundWorker 任务,包括当前正在执行的任务。如果当前正在执行一个任务并启动了一个新任务,则需要将旧任务标记为 AbortedAborted 任务与 Cancelled 的不同之处在于 Aborted 不允许进行任何进一步的 UI 更新。它应该被“静静地取消”。

我将 BackgroundWorker 包装在 AsyncTask 类中并添加了 IsAborted 位。检查 ProgressChangedRunWorkerCompleted 中的 IsAborted 位可防止进一步的 UI 更新。太棒了!

但是,这种方法失败了,因为当新任务启动时,CurrentTask 被替换为 AsyncTask 的新实例。因此,跟踪 CurrentTask 变得很困难。

如前所述,在 TODO: 中,我几乎想等到 CurrentTask 在中止后完成,然后再开始新任务。但我知道这会带来糟糕的用户体验,因为 UI 线程将被阻塞,直到旧任务完成。

是否有更好的方法来跟踪多个 AsyncTasks 以确保可以按需启动新任务并正确中止旧任务而无需进一步的 UI 更新?似乎没有跟踪 CurrentTask 的好方法...该 TPL 是否提供更好的方法来处理我所追求的?

以下是我的 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;
}

最佳答案

据我了解,您并不想真正中止线程,您只是希望它继续静默工作(即不更新 UI)?一种方法是保留一个 BackgroundWorker 列表,并在它们要“中止”时删除它们的事件处理程序。

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

这样你就可以跟踪所有的 worker 。由于 List 保持顺序,您将知道哪个是最新的(列表中的最后一个),但您可以在这里轻松地使用 Stack 如果您更喜欢。

关于c# - 跟踪多个 BackgroundWorker,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16919426/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com