0

I read this guide about the BackgroundWorker class.

I am trying to implement a reset button, so I added following code.

In Page.xaml:

<Button x:Name="buttonReset" Content="Reset" Click="buttonReset_Click"
                    Width="80" Height="30"/>

and in Page.cs:

    private void buttonReset_Click(object sender, RoutedEventArgs e)
    {
        if (bw.WorkerSupportsCancellation == true)
        {
            bw.CancelAsync();
        }

        // How to restart?

        bw.RunWorkerAsync(); // Raises busy exception

    }

But I get following error:

enter image description here

From italian:

This BackgroundWorker is busy and couldn't execute more than one task in the same time

This exactly occurs only when I press Start a then Reset.

Why? And how to fix?

shogitai
  • 1,823
  • 1
  • 23
  • 50
  • 3
    you can always just discard this instance of BGWorker just after cancelation, and then create new one. And you should use Task class instead of BGWorker in modern solutions – Krzysztof Skowronek Mar 23 '18 at 09:33
  • I try to add `bw.Dispose(); bw = new BackgroundWorker();` this avoids the exception, but the others buttons do not work anymore, so I think this suggestion doesn't solve my problem. :( Please note that `bw` is a global variable of the class. – shogitai Mar 23 '18 at 09:40
  • 1
    because when you make new isntance you have to set up everything again: ` bw.WorkerReportsProgress = true; bw.WorkerSupportsCancellation = true; bw.DoWork += new DoWorkEventHandler(bw_DoWork); bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);` – Krzysztof Skowronek Mar 23 '18 at 09:42
  • How about *not* using a BGW? That class became obsolete in 2012, it was completely replaced by async/await, Task.Run and the IProgress interface. – Panagiotis Kanavos Mar 23 '18 at 09:45
  • 1
    Simply change your method to `private async void button1_Click(...){ await Task.Run(()=>CallThatMethod()); txtStatus.Text="Tada!";}`. If you want cancellation, use a CancellationTokenSource and CancellationToken , eg `await Task.Run(()=>...,cts.Token);` – Panagiotis Kanavos Mar 23 '18 at 09:46
  • 1
    In any case the guide you link to is *ancient*. It's about Silverlight, an *abandoned* platform. Even back then though, people used Tasks, not BGW – Panagiotis Kanavos Mar 23 '18 at 09:49

1 Answers1

-1

Please note that this is a bad solution even if works

I tried this:

    private void buttonReset_Click(object sender, RoutedEventArgs e)
    {
        if (bw.WorkerSupportsCancellation == true)
        {
            bw.CancelAsync();

            while (bw.IsBusy)
            {
                DoEvents();
            }
        }

        bw.RunWorkerAsync();

    }

    public static void DoEvents()
    {
        Application.Current.Dispatcher.Invoke(DispatcherPriority.Background,
                                              new Action(delegate { }));
    }

This solved the problem.

In particular i added:

     while (bw.IsBusy)
     {
          DoEvents();
     }

where DoEvents() is defined:

    public static void DoEvents()
    {
        Application.Current.Dispatcher.Invoke(DispatcherPriority.Background,
                                              new Action(delegate { }));
    }

as mentioned (here).

Note: special thanks to a mysterious user who replied here but deleted his answer.

mjwills
  • 23,389
  • 6
  • 40
  • 63
shogitai
  • 1,823
  • 1
  • 23
  • 50
  • Bad answer. `Application.DoEvents()`. does *not* marshal calls to the dispatcher anyway, it's meant to allow the UI to process messages when you run a long job on the UI thread. What you did here was use a convoluted way to make the BGW start *another* thread. There's no need to use all that code just to run something in the background. Why are you using a BGW *at all*? – Panagiotis Kanavos Mar 23 '18 at 09:49
  • What does your worker method do anyway? Why don't you use `Task.Run` ? – Panagiotis Kanavos Mar 23 '18 at 09:53
  • @PanagiotisKanavos I have to update many progress bars listed into a ListBox in XAML. I launch a BGW for each proogress bar. Then some progress bar should be resetted. – shogitai Mar 23 '18 at 09:53
  • 1
    then you have multiple bugs. You **can't** update any UI element from inside a BGW worker method. That's what its Progress event is for. In the end its Done event is used to reset the progress bars. You don't need any of that code to just run a BGW and update 100 progress bars. With Task.Run though you need even *less* code – Panagiotis Kanavos Mar 23 '18 at 09:55
  • In any case, MVVM means that if you update a SomeProgress property all progress bars that bind to it will get updated. No need to run anything in the background. – Panagiotis Kanavos Mar 23 '18 at 09:56
  • 1
    Post and ask about what you actually want to do, not what you thought would be the solution. DataBinding makes updating multiple UI elements trivial. `async/await` makes working in the background without blocking easy. – Panagiotis Kanavos Mar 23 '18 at 09:57