从 backgroundworker c# 调用的方法中更新进程

Update process from within method called by backgroundworker c#

我有一个带有 gui 和 Rich Text Box 的应用程序,我在其中输出程序当前正在执行的操作,因为数据处理可能会很长。

为此我尝试了两种方法:

1 在 Backgroundworker 方法中,我可以调用以下代码:

GlobalVar.backgroundWorkerAppendText = task.Build_CSV_List();
Processchange();

而由于非静态上下文

,我无法在助手 class 中使用 Form1.Processchange();

2 因此,我尝试创建我的第一个事件处理程序。
这个想法是 helper.UpdateConsole() 会引发一个事件

public event EventHandler OnConsoleUpdate;
public void Consoleupdate()
{
    OnConsoleUpdate(this, EventArgs.Empty);
}

Backgroundworker 监听然后从其上下文中调用 Processchange

public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    StandardTasks task = new StandardTasks();
    Helper helper = new Helper();
    helper.OnConsoleUpdate += Processchange;
    task.DoSomeStuffHere()
}
public void Processchange(object sender=null, EventArgs e=null)
{
    //MessageBox.Show(GlobalVar.backgroundWorkerAppendText);
    GlobalVar.next = false;
    backgroundWorker1.ReportProgress(1);
    while (GlobalVar.next == false)
    {
        helper.TimeBreaker(100,"ms");
    }
}

不幸的是,这没有成功。一旦事件发生,我就会收到错误消息 System.NullReferenceException,在谷歌搜索后,我得出的结论是事件没有附加任何侦听器 eventhouh 我在 Backgroundworker 中附加了它。

编辑:OnConsoleUpdate() == null,如下面的屏幕截图所示

event = null

助手在另一个 class 文件“助手”中,这可能对解决方案很重要。

希望大家帮帮我。

欢迎来到 SO!

有几件事立即跳入脑海。

首先,让我们解决事件问题。你有正确的方法 - 你需要一个事件和方法来调用它,但该方法应该检查事件是否为 null.

基本上,这样做:

public event EventHandler OnConsoleUpdate;
public void ConsoleUpdate()
{
    OnConsoleUpdate?.Invoke(this, EventArgs.Empty);
}

上面使用了空条件运算符?。您可以阅读更多相关信息 on this MSDN page

第二件事...不清楚您的后台工作人员到底是什么。听起来像是您创建的某种习俗 class?它之所以重要,是因为 .NET 实际上有一个 BackgroundWorker class 用于 运行 操作……好吧,在后台。它还有一个 OnProgressChanged 事件,您可以连接到该事件可用于更新 UI (只记得将 WorkerReportsProgress 属性 设置为 true ).要使用上面提到的 BackgroundWorker,您不需要创建自己的任何事件。

以下是使用标准 .NET 的方法BackgroundWorker

System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();

void StartBackgroundTask()
{
    worker.DoWork += worker_DoWork;
    //if it's possible to display progress, use this
    worker.WorkerReportsProgress = true;
    worker.ProgressChanged += worker_ProgressChanged;
    //what to do when the method finishes?
    worker.RunWorkerCompleted += worker_RunWorkerCompleted;
    //start!
    worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    //perform any "finalization" operations, like re-enable disabled buttons
    //display the result using the data in e.Result
    //this code will be running in the UI thread
}

//example of a container class to pass more data in the ReportProgress event
public class ProgressData
{
    public string OperationDescription { get; set; }
    public int CurrentResult { get; set; }
    //feel free to add more stuff here
}

void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
    //display the progress using e.ProgressPercentage or e.UserState
    //this code will be running in the UI thread
    //UserState can be ANYTHING:
    //var data = (ProgressData)e.UserState;
}

void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    //this code will NOT be running in the UI thread!
    //you should NOT call the UI thread from this method

    int result = 1;
    //perform calculations
    for (var i = 1; i <= 10; i++)
    {
        worker.ReportProgress(i, new ProgressData(){ OperationDescription = "CustomState passed as second, optional parameter", CurrentResult = result });
        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
        result *= i;
    }

    e.Result = result;
}

现在,关于 BackgroundWorker class 的问题是它相当陈旧,对于当前的 .NET 版本,您可以使用 async / await 关键字轻松处理后台操作和UI 更新,但这可能超出了这个问题的范围。也就是说,async / await 的存在不会使 BackgroundWorker 的使用无效,它的用法非常简单。

您的代码中还有一件令人担忧的事情。

public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    StandardTasks task = new StandardTasks(); //<- you create a task
    Helper helper = new Helper(); // <- you create a helper
    helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper event
    task.DoSomeStuffHere(); // <- you do stuff with the task... but the task doesn't know about your helper above! Does `StandardTasks` use `Helper`? If so, how?
}

请注意,除非static,否则事件不是全球性的。因此,在 class 的一个实例中连接到一个事件不会导致该 class 的另一个实例到 "fire" 该事件。似乎解决问题的一种方法是使 StandardTasks class 将 Helper 作为构造函数参数之一,因此代码如下所示:

Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper class event to actually do something
StandardTasks task = new StandardTasks(helper); //<- you create a task which will use the helper with the hooked up event above