更改后台工作程序中的计时器间隔DoWork禁用计时器[C#]

时间:2015-07-22 08:32:53

标签: c# multithreading timer backgroundworker intervals

我遇到了在backgroundworker的DoWork事件中更改计时器Interval的问题。通过单击按钮更改间隔时,计时器停止并且不会再次启动。

有谁知道如何解决这个问题?

简单代码:

    public Form1()
    {
        InitializeComponent();
        timerTest.Tick += new EventHandler(timerTest_Tick);
        timerTest.Interval = 1000;
        timerTest.Start();
    }

    private void buttonTest_Click(object sender, EventArgs e)
    {
        push = true;
    }

    private void timerTest_Tick(object sender, EventArgs e)
    {
        ticks++;
        labelTest.Text = ticks.ToString();
        if(running == false)
        {
            running = true;
            backgroundWorkerTest.RunWorkerAsync();
        }
    }

    public void activate()
    {
        timerTest.Stop();
        timerTest.Interval = 4000;
        timerTest.Start();
    }

    private void DoWork(object sender, DoWorkEventArgs e)
    {
        while(running)
        {
           if(push == true)
           {
               activate();  
           }
        }
    }

    private void Completed(object sender, RunWorkerCompletedEventArgs e)
    {
        running = false;
    }
}

}

4 个答案:

答案 0 :(得分:0)

您永远不会将push设置为false。

因此,以下代码:

    while(running)
    {
       if(push == true)
       {
           activate();  
       }
    }

会在紧急循环中不断调用activate()activate()停止计时器然后重新启动计时器,调用它之间的时间将远远小于计时器间隔。因此,定时器永远不会留下足够的时间来发射。

在任何情况下,为什么不直接从activate()致电buttonTest_Click()

答案 1 :(得分:0)

尝试使用UI线程调度程序调用您的activate方法。 (假设赢表?

this.Invoke(new Action(activate));

原因是您的timer是一个UI控件,并且您在单独的线程上更新Interval。这将抛出跨线程异常

为什么您没有看到异常?DoWork中的BackgroundWorker方法引发异常时,它将传播到{{1} } 方法。因此,您应该始终查看Completed以查看是否发生了异常。

e.Error

答案 2 :(得分:0)

我花了一段时间,但我发现了什么是错的。我会给你发一个工作代码,万一有人会遇到同样的问题。

公共部分类Form1:表单     {         public int ticks = 0;         public bool running = false;         public bool push = false;

    public Form1()
    {
        InitializeComponent();
        timerTest.Tick += new EventHandler(timerTest_Tick);
        timerTest.Interval = 1000;
        timerTest.Start();
    }

    private void buttonTest_Click(object sender, EventArgs e)
    {
        push = true;
    }

    private void timerTest_Tick(object sender, EventArgs e)
    {
        ticks++;
        labelTest.Text = ticks.ToString();
        if(running == false)
        {
            running = true;
            backgroundWorkerTest.RunWorkerAsync();
        }
    }

    public void activate()
    {
        ZmienIntervalNaAwaryjny = true;
    }
    public bool ZmienIntervalNaAwaryjny = false;
    private void DoWork(object sender, DoWorkEventArgs e)
    {

           if(push == true)
           {
               activate();
           }
    }

    private void Completed(object sender, RunWorkerCompletedEventArgs e)
    {
        if(ZmienIntervalNaAwaryjny == true)
        {
            timerTest.Stop();
            timerTest.Interval = 12000;
            timerTest.Start();
        }
        ZmienIntervalNaAwaryjny = false;
        running = false;
    }
}

答案 3 :(得分:0)

我可以看到这是很久以前问过的,但仅供参考:

一般来说,与后台工作程序(任务)结合使用计时器或线程(记住计时器是system.threading)时,切勿在不知道工作程序正在做什么的情况下尝试随机更改线程属性。

在分配DoWork处理程序以同时准备后台工作程序Progress和Complete处理程序时,这始终是一个好习惯。 在每个周期,报告进度或完成情况,这将使您有机会进行检查并根据需要修改其他线程属性。

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
 while (!worker.CancellationPending)
{
  // do task 1 as per the timer1 interval
  // do task 2 as per such and such .....
  // if I call ChangeInterval here I'll be fiddling with another thread when 
  //  this is still in progress 
  // that a full loop, Progress will be reported now

  }
 }
   private void backgroundWorker1_ProgressChanged(object sender,ProgressChangedEventArgs e)
     {
       // Now as the Do work is not in progress
       // do something 
       // check if the user wanted to change the interval ?
       // if yes then
       ChangeInterval(6000);
       // here the progress reporting is done so it will go back to DoWork with the 
       // NewInterval Value in place and the timer enabled
     }

     private void ChangeInterval(int NewInterval)
     {
       timer1.Enabled =false;
       timer1.Interval = NewInterval;
       timer1.Enabled = true;
     }