Search code examples
c#asynchronousasync-awaitbackgroundworker

C# backgroundworker RunworkerCompleted vs async await


Updated with answers: The true way of wait until a number of different tasks to be finished would need async await instead of background worker.

#

I know there are numerous discussion about backgroundworker but I've being searched around and cannot find the answer.

Here is my code example(basic logic, the actual code is much longer), I wonder if there is a way to get around this:

 BackgroundWorker MCIATS1Worker = new BackgroundWorker();
    private AutoResetEvent _MCIATS1WorkerResetEvent = new AutoResetEvent(false);

    public MainWindow()
    {
        InitializeComponent();

        MCIATS1Worker = new BackgroundWorker();
        MCIATS1Worker.DoWork += new DoWorkEventHandler(MCIATS1Worker_DoWork);
        MCIATS1Worker.WorkerReportsProgress = true;
        MCIATS1Worker.WorkerSupportsCancellation = true;
        MCIATS1Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(MCIATS1_RunWorkerCompleted);

        for (int i = 1; i <= 10; i++)
        {
            //some code
            MCIATS1Worker.RunWorkerAsync();
            _MCIATS1WorkerResetEvent.WaitOne();
        }

    }

DoWork and runworkercompleted

void MCIATS1Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //do something here
    }

    void MCIATS1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        MessageBox.Show("hello world");
        _MCIATS1WorkerResetEvent.Set();
    }

For some reasons, the MCIATS1_RunWorkerCompleted won't be triggered until the loop finished. And apparently the WaitOne is holding the loop.
Here is my question,

why RunWorkerCompleted won't be trigger the RunWorkerCompleted when the worker is actually finished the work?

Thank you.

###UPDATED SOLUTION

This is the right way of doing it.

private async void WhateverFunction()
   {
    await Task.WhenAll(MCIATS1WorkerDoWorkAsync(param),...other tasks);
    }


private Task MCIATS1WorkerDoWorkAsync(bkgWorkParameter param)
    {
        return Task.Run(() =>
        {
            //Do whatever
        });
    }

Solution

  • Depend on what kind of work your MCIATS1Worker_DoWork method do, you can consider to use async-await approach, which makes code a little bid more cleaner.

    private async Task MCIATS1WorkerDoWorkAsync()
    {        
        await Task.Delay(1000) // do something asynchronously for 1 second
    }
    
    private async void MainWindow_Load(object sender, EventArgs e)
    {
         for (int i = 1; i <= 10; i++)
         {
            //some code
            await MCIATS1WorkerDoWorkAsync();
            MessageBox.Show("hello world");
         }       
    }
    

    Message box will be shown 10 times every 1 second. await keyword will continue loop only after MCIATS1WorkerDoWorkAsync method has successfully finished.

    With async-await your form will remain responsive and if DoWork method do some IO operations, then you will not start another thread (as BackgroundWorker do) and whole execution will happens on one thread.