C# 如何在RunWorkerCompletedEventArgs对象中设置UserState?
大家好。 我有一个运行Worker类实例的BackgroundWorker对象数组。当我调用Worker类时,对象实例完成了它的工作,然后代码耗尽(循环完成)。我可以监听RunWorkerCompleted()事件,但当它调用我设置的委托时,我需要知道哪些工作对象刚刚完成 我在委托的RunWorkerCompletedEventArgs中看到一个UserState属性,但我不知道如何在Worker对象完成时设置它 有什么想法吗 my WorkManager.cs类中的代码片段C# 如何在RunWorkerCompletedEventArgs对象中设置UserState?,c#,backgroundworker,C#,Backgroundworker,大家好。 我有一个运行Worker类实例的BackgroundWorker对象数组。当我调用Worker类时,对象实例完成了它的工作,然后代码耗尽(循环完成)。我可以监听RunWorkerCompleted()事件,但当它调用我设置的委托时,我需要知道哪些工作对象刚刚完成 我在委托的RunWorkerCompletedEventArgs中看到一个UserState属性,但我不知道如何在Worker对象完成时设置它 有什么想法吗 my WorkManager.cs类中的代码片段 public Wo
public Worker AddWorker()
{
Worker w = new Worker();
_workers.Add(w.WorkerID,w);
BackgroundWorker bg = new BackgroundWorker();
_bgworkers.Add(bg);
bg.DoWork += w.Start;
bg.WorkerReportsProgress = true;
bg.WorkerSupportsCancellation = true;
bg.ProgressChanged += ProcessWorkerMessage;
bg.RunWorkerCompleted += WorkerFinished;
w.WorkManager = this;
w.BackgroundWorker = bg;
bg.RunWorkerAsync(w);
return w;
}
public void WorkerFinished(object sender, RunWorkerCompletedEventArgs e)
{
if (_onManagerEvent != null)
_onManagerEvent(new ManagerEvent { EventDate = DateTime.Now, Message = "Worker ??? successfully ended." });
}
因此,当我的Worker对象在其Start()方法中完成循环时,我该如何填充传递给我的WorkerFinished方法()的RunWorkerCompleteEventArgs对象“e”的userState属性
谢谢您的
Worker
类上的Start
方法可以设置dowworkeventargs
参数的Result
属性。下面是一个例子:
void Start(object sender, DoWorkEventArgs e)
{
//Do your loop and other work.
e.Result = this;
}
然后在finish事件处理程序中,您可以检索e。结果:
public void WorkerFinished(object sender, RunWorkerCompletedEventArgs e)
{
//You should always check e.Cancelled and e.Error before checking e.Result!
// ... even though I'm skipping that here
Worker w = e.Result as Worker;
if( w != null)
{
if (_onManagerEvent != null)
_onManagerEvent(new ManagerEvent
{
EventDate = DateTime.Now,
Message = String.Format("Worker {0} successfully ended."
, w.ToString())
});
}
}
UserState
是BackgroundWorker
中的一个已知错误:
(archive.org链接…原始链接已失效)
我过去在您的情况下所做的是使用
RunWorkerCompletedEventArgs.Result
(正如Philip所建议的),或者,如果可能的话,让我的员工从BackgroundWorker
(然后,我可以添加任意多的额外状态,并将整个worker作为发送者参数添加到由BackgroundWorker
引发的事件中,同时仍然能够使用Result
实现其预期目的).十五年后,lesscode的回答中提到的错误尚未修复,即使在Microsoft将Winforms移植到.NET Core之后也是如此。我还有一个额外的要求,那就是当工人被取消时,我需要获得“用户对象”
由于您无法设置该用户对象,并且在工作进程被取消时无法访问结果,因此我必须将取消与RunWorkerCompletedEventArgs
实现分开进行跟踪
这是我的解决方案。首先,创建一个结果对象,它作为用户对象执行双重任务(对不起),比如
private void HandleWorkerDoWork(object sender, DoWorkEventArgs e)
{
var stateAndResult = new WorkerStateAndResult(...);
e.Result = stateAndResult;
try
{
// do the work and check for cancellation. if cancellation happens, set Canceled
// instead of using built-in e.Canceled property
stateAndResult.Canceled = ResultOfActualWork();
}
catch
{
// handle errors, again, not using built-in mechanism
stateAndResult.Error = true;
}
finally
{
// any cleanup
}
}
类工作状态和结果
{
公共布尔错误{get;set;}
公共bool已取消{get;set;}
//其他状态/结果。。。
}
然后,在worker的处理程序中,立即将Result
属性设置为WorkerStateAndResult
的实例。在处理程序中,当取消worker时,您不会将DoWorkerEventArgs.Cancelled
设置为true
;相反,您将在状态对象上设置属性;对于错误,情况也是如此案例。你的处理者最终看起来像
private void HandleWorkerDoWork(object sender, DoWorkEventArgs e)
{
var stateAndResult = new WorkerStateAndResult(...);
e.Result = stateAndResult;
try
{
// do the work and check for cancellation. if cancellation happens, set Canceled
// instead of using built-in e.Canceled property
stateAndResult.Canceled = ResultOfActualWork();
}
catch
{
// handle errors, again, not using built-in mechanism
stateAndResult.Error = true;
}
finally
{
// any cleanup
}
}
最后,在RunWorkerCompleted
处理程序中,您可以访问包含所有结果和状态的结果,并且您可以检查错误
和取消
属性以执行所需的任何逻辑:
private void HandleAnalyzerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// this would normally throw if error or canceled, but not anymore!
var result = (WorkerStateAndResult)e.Result;
if (result.Canceled)
{
// do canceled logic
}
else if (result.Errored)
{
// do error logic
}
else
// do regular logic using result
}
谢谢Philip,这就成功了。你关于总是检查e的评论。取消是关键。我实际上是通过调用BackgroundWorker对象的CancelAsync()来停止我的工作线程方法。这导致RunWorkercompletedEventArgs结果属性没有我的原始对象。我已进行重构,通过在worker对象上设置属性(以线程安全的方式)来停止worker只是在我的工作者代码循环中检查一下。如果我看到它的信号,我就退出循环,瞧,RunWorkercompletedEventArgs arg在e.Result中有我的对象。我没有想到继承背景工作者。添加得不错。阅读你发布的链接,日期显示这个bug已经存在15年了!