【问题标题】:Changing Timer Interval in Backgroundworker DoWork Disables the Timer [C#]在 Backgroundworker DoWork 中更改定时器间隔会禁用定时器 [C#]
【发布时间】:2015-07-22 08:32:52
【问题描述】:

我在后台工作人员的 DoWork 事件中更改计时器间隔时遇到问题。通过单击按钮更改间隔时,计时器停止并且不再启动。

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

简单代码:

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

}

【问题讨论】:

  • Timer 类是线程安全的,但不是任何人都喜欢的方式。只要您不调用 Stop(),它就可以正常工作。代码太假了,无法给出正确的建议。

标签: c# multithreading timer backgroundworker intervals


【解决方案1】:

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

因此,如下代码:

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

将在一个紧密的循环中不断地调用activate()activate() 停止计时器然后重新启动它,调用它之间的时间将远小于计时器间隔。因此,计时器永远不会被留到足够长的时间来触发。

无论如何,你为什么不直接从buttonTest_Click()拨打activate()

【讨论】:

    【解决方案2】:

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

    当涉及到定时器或线程(记住定时器是 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;
         }
     
    

    【讨论】:

      【解决方案3】:

      尝试使用 UI 线程的调度程序调用您的 activate 方法。 (假设获胜形式?

      this.Invoke(new Action(activate));
      

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

      您为什么看不到异常?当您的BackgroundWorker 中的DoWork 方法抛出异常时,它将被传播到Completed 方法。所以你应该经常查看e.Error,看看是否发生了异常。

      private void Completed(object sender, RunWorkerCompletedEventArgs e)
      {
          if(e.Error != null)
          {
              // Oh no something went wrong...
          }
      
          running = false;
      }
      

      【讨论】:

        【解决方案4】:

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

        公共部分类 Form1 : Form { 公共 int 滴答声 = 0; 公共布尔运行=假; 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;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2015-08-14
          • 2016-12-14
          • 2021-09-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多