Search code examples
c#.netwpfbackgroundworker

backgroundworker starts more than once


I have a issue that I really dont know why it occurs at all. I wpf c# application that use a timer to start a backgroundworker, sometimes the backgroundworker start the task twice, and I don't know why. The code I use is this....

private void startScheduledTask()
{
    // Timer settings and start
    dpTimer.Interval = TimeSpan.FromMilliseconds(CalculateTimerInterval(CHECK_INTERVAL));
    dpTimer.Tick += new EventHandler(StartScheduledActivity);
    dpTimer.Start();
}

private void StartScheduledActivity(Object sender, EventArgs args)
{
    // Timer tick has occured, start scheduled work
    StartScheduledWork();
    dpTimer.Interval = TimeSpan.FromMilliseconds(CalculateTimerInterval(CHECK_INTERVAL));
}

private void StartScheduledWork()
{
    MyHeavyWorker = new System.ComponentModel.BackgroundWorker();

    if ((!MyHeavyWorker.IsBusy) && (MyHeavyWorker != null))
    {
        MyHeavyWorker.WorkerReportsProgress = true;
        MyHeavyWorker.WorkerSupportsCancellation = true;
        MyHeavyWorker.ProgressChanged += MyHeavyWorker_ProgressChanged;
        MyHeavyWorker.DoWork += MyHeavyWorker_DoWork;
        MyHeavyWorker.RunWorkerCompleted += MyHeavyWorker_RunWorkerCompleted;
        MyHeavyWorker.RunWorkerAsync();
    }
}

private void MyHeavyWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
   // This method sometime run twice at a time
   FetchSomeFiles();
}



        public int CalculateTimerInterval(int minute)
    {
        if (minute <= 0)
        {
            minute = 60;
        }
        DateTime CurrTime = DateTime.Now;
        DateTime now = DateTime.Now;

        DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
        TimeSpan interval = future - now;

        NextExecutionTime = future.ToShortTimeString();
        NextExecutionDateTime = NextExecutionTime.ToString();

        return Convert.ToInt32(interval.TotalMilliseconds);
    }                       

Can anyone see why the method FetchSomeFiles sometimes runs twice at the same time?


Solution

  • It's quite simply because you are each time initializing a new instance of your backgroundworker - so if your timer event occurs before the previous backgroundworker is done it will start a second time with another bg Worker instance. Keep your Backgroundworker reference on class level and initialize it only once.

    Do the same thing with the eventhandlers you are adding - move them to the class constructor or to a method called once when your object is instanciated.

        //Put this line on class level and only initialize it once.
        MyHeavyWorker = new System.ComponentModel.BackgroundWorker();
    
        //Call this once to initialize your Backgroundworker
        public void InitializeBackgroundWorker()
        {
            MyHeavyWorker.WorkerReportsProgress = true;
            MyHeavyWorker.WorkerSupportsCancellation = true;
            MyHeavyWorker.ProgressChanged += MyHeavyWorker_ProgressChanged;
            MyHeavyWorker.DoWork += MyHeavyWorker_DoWork;
            MyHeavyWorker.RunWorkerCompleted += MyHeavyWorker_RunWorkerCompleted;
        }
    

    Then check for the MyHeavyWorker.IsBusy of your one and only instance to check if it is currently doing some work before deciding to call RunWorkerAsync().

    Another method would also be to just stop your timer with dpTimer.Stop() in StartScheduledActivity before you launch your BackgroundWorker and call dpTimer.Start() again in MyHeavyWorker_RunWorkerCompleted. Of course you will have to reconsider how you would like to calculate your next interval since with this solution the countdown does start after your backgroundworker is done - which could be considerably later than the point of the start.