简体   繁体   中英

Update process from within method called by backgroundworker c#

I have an application with a gui and a Rich Text Box where i output what the program is currently doing since data processing can be quite long.

I tried two approaches for that:

1 In the Backgroundworker Method I can just call the following code fine:

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

Whereas i cannot use Form1.Processchange(); in the helper class due to the non static context

2 Therefore I tried to create my very first eventhandler.
The Idea was that helper.UpdateConsole() would raise an event

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

to which the Backgroundworker listens and then calls Processchange from its context

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

Unfortunately this was was not successful. As soon as rising the Event I get the errormessage System.NullReferenceException which -after googling- leads me to the conclusion that there is no listerner attached to the event eventhouh I attached it in the Backgroundworker Do work.

Edit: the OnConsoleUpdate() == null as shown on the screenshot below

event = null

The helper is in another class file "helpers" which might be important for a solution.

i hope you guys can help me out.

Welcome to SO!

A few things immediately jump to mind.

First, let's get the event issue out of the way. You've got the correct approach - you need an event and method to call it, but that method should check if the event is null .

Basically, do this:

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

The above makes use of ? , a null-condition operator. You can read more about it on this MSDN page .

Second thing... it's unclear what your background worker actually IS. It sounds like it's some kind of custom class you crated? The reason it's important is because .NET actually has a BackgroundWorker class used for running operations... well, in the background. It also has an OnProgressChanged event which you can hook up to which could be used to update the UI (just remember to set the WorkerReportsProgress property to true ). And to use the BackgroundWorker mentioned above, you shouldn't need to create any events of your own.

Here's how you can use the standard .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;
}

Now, the thing about the BackgroundWorker class is that it is rather old, and with current .NET versions you can use the async / await keywords to easily handle background operations and UI updates, but this probably is going outside the bounds of this question. That said, the existence of async / await doesn't invalidate the use of BackgroundWorker which is pretty simple in its usage.

There's one more worrisome thing in your code.

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?
}

Do note that events, unless made static , aren't global. So hooking up to an event in one instance of a class won't cause another instance of that class to "fire" that event. It seems one way to fix your issues would be to make the StandardTasks class take Helper as one of the constructor parameters, so the code would look like this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM