C# 如何在RunWorkerCompletedEventArgs对象中设置UserState?

C# 如何在RunWorkerCompletedEventArgs对象中设置UserState?,c#,backgroundworker,C#,Backgroundworker,大家好。 我有一个运行Worker类实例的BackgroundWorker对象数组。当我调用Worker类时,对象实例完成了它的工作,然后代码耗尽(循环完成)。我可以监听RunWorkerCompleted()事件,但当它调用我设置的委托时,我需要知道哪些工作对象刚刚完成 我在委托的RunWorkerCompletedEventArgs中看到一个UserState属性,但我不知道如何在Worker对象完成时设置它 有什么想法吗 my WorkManager.cs类中的代码片段 public Wo

大家好。 我有一个运行Worker类实例的BackgroundWorker对象数组。当我调用Worker类时,对象实例完成了它的工作,然后代码耗尽(循环完成)。我可以监听RunWorkerCompleted()事件,但当它调用我设置的委托时,我需要知道哪些工作对象刚刚完成

我在委托的RunWorkerCompletedEventArgs中看到一个UserState属性,但我不知道如何在Worker对象完成时设置它

有什么想法吗

my WorkManager.cs类中的代码片段

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年了!