如何在RunWorkerCompletedEventArgs对象中设置UserState?

时间:2010-11-30 03:02:29

标签: c# backgroundworker

全部。 我有一组运行Worker类实例的BackgroundWorker对象。当我调用Worker类时,对象实例会执行它,然后用尽代码(循环结束)。我能够收听RunWorkerCompleted()事件,但是当它调用我设置的委托时,我需要知道我的哪些Worker对象刚刚完成。

我在RunWorkerCompletedEventArgs中看到了一个UserState属性,该属性来自我的委托,但我不知道如何在我的Worker对象中设置它,因为它正在完成。

有什么想法吗?

来自我的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属性?

由于

3 个答案:

答案 0 :(得分:13)

Start类上的Worker方法可以设置Result参数的DoWorkEventArgs属性。这是一个例子:

void Start(object sender, DoWorkEventArgs e)
{
   //Do your loop and other work.
   e.Result = this;
}

然后在完成事件处理程序中,您可以检索e.Result:

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

答案 1 :(得分:3)

UserState中的BackgroundWorker事件是RunWorkerCompletedEventArgs.Result中的已知错误:

http://www.pluralsight-training.net/community/blogs/mike/archive/2005/10/21/15783.aspx(archive.org链接...原始链接已死)

我过去在遇到你的情况时所做的就是使用BackgroundWorker(如菲利普建议的那样),或者,如果可能的话,让我的工作人员来自BackgroundWorker(那么我可以添加尽可能多的额外状态,并将整个worker作为Result引发的事件的sender参数,同时仍然可以将{{1}}用于其预期目的。

答案 2 :(得分:1)

十五年后,甚至在Microsoft将Winforms移植到.NET Core之后, lesscode 答案中提到的错误仍未得到修复。我还有其他要求,即在取消工作程序时需要获取“用户对象”。

由于在取消工作程序时无法设置该用户对象,并且无法访问结果,因此我不得不与RunWorkerCompletedEventArgs 实现分开跟踪取消操作。

这是我的解决方案。首先,创建一个结果对象,将其作为用户对象承担双重责任(对不起SRP),类似

class WorkerStateAndResult
{
    public bool Errored { get; set; }
    public bool Canceled { get; set; }
    // other state/results...
}

然后,在工作人员的处理程序中,立即将Result属性设置为WorkerStateAndResult的实例。在处理程序内部,取消工作程序时,不会将DoWorkEventArgs.Canceled设置为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处理程序中,您可以访问具有所有结果和状态的result,并且可以检查ErrorCanceled属性以执行任何逻辑操作需要:

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
}