wjtk4444
wjtk4444

Reputation: 47

BackgroundWorker works n times for every n-th run of it

What's the problem:

I have a wpf app, with a function "install" assigned to a button. It copies and deletes a few files. In button_click function I'm checking if "install" can be run and if it can I'm running it. This function is in another class so I'm running it by:

class1 class = new class1();
class.function();

and the function is:

public void install()
{
    worker.RunWorkerAsync();
    worker.WorkerSupportsCancellation = true;
    worker.WorkerReportsProgress = true;
    worker.DoWork += (s, args) =>
    {
        for(int i=0;i<100;i++)
        {
            //do some work;
            worker.ReportProgress(i);
        }

        MessageBox.Show("done");
    };

    worker.ProgressChanged += (s, args) =>
    {
        // report progress
    };

    worker.RunWorkerCompleted += (s, args) =>
    {
        worker.CancelAsync();  //not sure if it's needed, it changes nothing
        //reset some values
    };
 }

Yeah, something like that. Sorry if it looks a bit retarded but I'm new here and still learning how to paste elements of code :P (if needed i can upload whole project or pastebin some parts)

Whole thing works well, but while I'm clicking install button for 2nd, 3rd, ..., n-th time the worker is doing it's work n times (see the thread name). And I'm out of ideas why. Am I missing something like worker.close() or whatever ?

EDIT: http://pastebin.com/YR9ZHCCY <- Here, it looks much better

Upvotes: 0

Views: 107

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70701

Every time you handle the button click, you are subscribing your worker method to the DoWork event. In C#, delegates are "multicast", meaning that they can have multiple invocation targets. Every time you subscribe the worker method, you add an invocation target, causing that method to be called an additional time. So for N button presses, you get N copies of the same invocation target method in the DoWork event delegate.

Likewise the other events, ProgressChanged and RunWorkerCompleted.

If you want to keep a persistent BackgroundWorker instance, you should configure it just once when you initialize it (e.g. by setting properties and events in the Visual Studio Designer). If you want to configure it anew each time the button is clicked, then you should not keep a persistent BackgroundWorker instance.

For example, the cheesy approach, add this to the beginning of your install() method:

if (worker != null)
{
    worker.Dispose();
}
worker = new BackgroundWorker();

The non-cheesy approach involves finding the initialization of the BackgroundWorker object and putting all the initialization there. I don't know how this shows up in the WPF designer UI...in Forms, you get a BackgroundWorker component at the bottom of the owner form's design window; you can click the component and then edit the properties and event handlers via the Properties window.

Upvotes: 2

Related Questions