backgroundworker不止一次启动

时间:2014-10-06 07:35:58

标签: c# .net wpf backgroundworker

我有一个问题,我真的不知道它为什么会发生。我wpf c#应用程序使用计时器启动后台工作,有时后台工作者启动任务两次,我不知道为什么。我使用的代码就是这个....

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

任何人都可以看到为什么方法FetchSomeFiles有时会同时运行两次?

2 个答案:

答案 0 :(得分:1)

这很简单,因为你每次都在初始化你的背景工作者的一个新实例 - 所以如果你的计时器事件发生在前一个背景工作者完成之前,它将与另一个bg工作者实例开始第二次。将您的Backgroundworker引用保持在类级别并仅初始化一次。

对要添加的事件处理程序执行相同的操作 - 将它们移动到类构造函数或者在对象实例化时调用一次的方法。

    //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;
    }

然后在决定拨打MyHeavyWorker.IsBusy之前,检查您的唯一实例RunWorkerAsync()以检查它是否正在执行某些工作。

另一种方法是在启动BackgroundWorker之前在dpTimer.Stop()中使用StartScheduledActivity停止计时器,然后在dpTimer.Start()再次呼叫MyHeavyWorker_RunWorkerCompleted。当然,您必须重新考虑如何计算下一个间隔,因为使用此解决方案后倒计时确实在您的后台工作完成后开始 - 这可能要比开始时间晚得多。

答案 1 :(得分:0)

检查

if MyHeavyWorker.IsBusy

在DoWork()方法内启动任务之前。此方法将检查DoWork()是否仍在运行,并且在完成之前不会再启动此方法的另一次调用