- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个 WPF
应用程序,我正在使用 BackgroundWorker
组件从后端检索一些数据并将其显示在 UI 中。
BackgroundWorker
有 WorkerReportsProgress = true
以便 UI 可以定期更新。 BackgroundWorker
也有 WorkerSupportsCancellation = true
以便它可以被用户取消。一切都很好!
我在尝试实现第三个更复杂的行为时遇到了问题。基本上,用户需要能够灵活地随时启动新的 BackgroundWorker
任务,包括当前正在执行的任务。如果当前正在执行一个任务并启动了一个新任务,则需要将旧任务标记为 Aborted
。 Aborted
任务与 Cancelled
的不同之处在于 Aborted
不允许进行任何进一步的 UI 更新。它应该被“静静地取消”。
我将 BackgroundWorker
包装在 AsyncTask
类中并添加了 IsAborted
位。检查 ProgressChanged
和 RunWorkerCompleted
中的 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/
在我的应用程序中,我在添加到我的列表框之前通过打开的 Wireshark 进程检查我的文件。这是添加目录单击事件,它获取根文件夹并检查此文件夹和子文件夹中的所有文件: private void btn
我有一个使用异步后台工作程序执行批处理文件的程序。这是代码: public static void Execute(CmdObj obj, bool batch) { CmdObj = obj
我正在尝试在项目中执行数据库密集型任务。这是一个演练: 我们需要搜索我们的 worker 数据库,我们称之为 Locums,并找到一个适合特定工作的人。当我们决定处理 x 个作业时,此过程开始。因此,
首先,我还是个初学者,如果您能耐心一点,我将不胜感激:) 今天我一直在为这件事绞尽脑汁。 问题是,我想运行三个不同的后台程序。但是我想等到一个运行完再运行下一个,依此类推。 每个后台 worker 都
我需要确保 BackgroundWoker 在被调用之前不忙,所以我检查 IsBusy 并调用 CancelAsync如果是: if (bgWorker.IsBusy)
我的目标是: 用户在组合框中输入完整或部分计算机名 按钮单击事件启动后台工作程序将计算机名传递给 DoWork 方法 DoWork 方法在 ActiveDirectory 中搜索计算机名并将集合传递给
每次我的代码需要与网络或数据库通信时,我都会使用后台工作人员,我是否可以使用太多,执行这些任务的正确方法是什么? 如果我不使用后台工作程序,则在远程主机关闭等情况下,gui会锁定,因此使用后台工作程序
关于 BGW 长期运行的任何想法建议? 最佳答案 是的 :)。在 BackgroundWorker 或 ThreadPool 中进行长时间运行的操作并没有本质上的错误……如果由于长时间运行的操作而导致
学习构建多线程 WPF 应用程序我读到了一些使用 BackgroundWorker 的限制,这对我来说不是很清楚。请帮我理解: 如果我不仅想要一个线程在 UI 的幕后工作,而且可能有多个线程,它们彼此
问题:重新使用 .NET Backgroundworker,有没有办法让异常正常传递回主线程? 背景: 目前在我的 WinForms 应用程序中,我有通用异常句柄,如果(a)自定义应用程序异常然后呈现
在尝试实现一个简单的 BackgroundWorker 时,我遇到了臭名昭著的“跨线程操作无效”异常。我花了几个小时阅读我能找到的关于这个主题的所有内容,包括关于 SO 的许多相关问题,但我就是不明白
有没有办法缩短我的 BackgroundWorker.CancellationPending 检查点? 例如,有没有办法像下面的示例代码一样封装return: //REAL CODE (CURRENT
嗨,我在处理完成后,无法将在BackgroundWorker的DoWork处理程序内部生成的图像数据分配给图像对象。我收到一条错误消息,指出“调用线程无法访问此对象,因为其他线程拥有它”。错误行是 P
如何获得有意义的BackgroundWorker.Error当DoWork必须调用可能引发异常的委托(delegate)? 我正在实现一个静态 MsgBox公开向用户传达自定义消息的各种方式(使用自定
我知道您可以在首次启动 backgroundworker 时通过 RunWorkerAsync 函数调用传递参数,但是您可以在它已经启动后向它传递数据吗?或者我是否需要创建自己的并发形式来处理从不同线
我有一个风格问题,关于我应该在 Windows 窗体应用程序上使用的后台线程实现的选择。目前,我的表单上有一个 BackgroundWorker,它具有无限 (while(true)) 循环。在此循环
我正在尝试在 .NET 1.1 中实现一个 BackgroundWorker(因为没有任何东西),而且我不太精通线程和委托(delegate)。 现在我有一个名为 BackgroundWorker 的
foreach (string file in listToConvert) { BackgroundWorker backgroundWorker = new BackgroundWorke
我正在制作我的第一个 C# GUI。它使用 BackgroundWorker 来运行计算量大的模拟。模拟会定期报告(通过 ProgressChanged 事件)需要在 GUI 中显示的大量信息。 GU
我想从一个表单启动一个后台 worker 。 private void button2_Click(object sender, EventArgs e) { back
我是一名优秀的程序员,十分优秀!