我有一个问题,我真的不知道它为什么会发生。我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有时会同时运行两次?
答案 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()是否仍在运行,并且在完成之前不会再启动此方法的另一次调用