【问题标题】:While sequence inside a timer tick in C#在 C# 中的计时器滴答内序列
【发布时间】:2013-10-15 13:18:20
【问题描述】:

我在 C# 中有一个 1 秒的计时器,其中有一个 while 序列。我的问题是,如果 while 序列在 1 秒之前没有完成,计时器会滴答作响,然后从头开始重新开始 while 吗?

代码的一部分如下,它的作用是循环选择对象并改变一些东西。那么,如果选择了很多对象,并且我需要超过 1 秒的时间来更改它们,它们会全部更改吗?

附:我实际上希望打破循环;大量对象只会被错误选择,但我只是想确保避免这种可能性。 :)

private void timer1_Tick(object sender, EventArgs e)
        {
            TSM.ModelObjectEnumerator myEnum = null;
            myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();

            while (myEnum.MoveNext())
            {
                if (myEnum.Current != null)
                {....}
            }
         } 

【问题讨论】:

  • 如果你想确保你的任务在你允许计时器再次滴答之前完成,你为什么不使用只滴答一次的计时器呢?或者在滴答开始时停止计时器,然后在滴答结束时重新启动。
  • 你说的是哪个定时器? .Net fw中有很多定时器
  • 我忘了在最初的问题中提到:我希望 while 循环被中断。选择所有对象或选择大量对象只会错误地发生,这就是为什么我要中断while。
  • 听起来你想在Timer Tick处理之前验证所选对象的类型/数量。

标签: c# timer while-loop


【解决方案1】:

是的,计时器滴答声可以同时发生。这意味着您的计时器必须是线程安全的。

除了对于 UI 计时器类 (WinForms/WPF)。它们的刻度函数在 UI 线程上运行。使用DoEvents,即使在那里也可能导致重入,这是避免DoEvents 的另一个原因。

【讨论】:

  • DoEvents() 也可以在 Winform 计时器中再次触发 Tick :)
【解决方案2】:

解决方法是在 while 事件顶部禁用计时器,并在退出 while 事件时重新启用它。

【讨论】:

    【解决方案3】:

    while 循环不会因为计时器再次计时而中断。但无论如何,最好的办法是在事件处理程序开始时禁用计时器,然后在结束时重新启用它。

    【讨论】:

      【解决方案4】:

      您总是可以尝试类似的方法,这样您就可以避免让多个计时器计时并启动进程。用记事本写的,所以请原谅任何严重的拼写错误

      private Timer _systemTimer = null;
      
      public MyApp()
      {
      _systemTimer = new Timer("how ever you set your 1 second);
      // Create your event handler for when it ticks over
      _systemTimer.Elapsed += new ElapsedEventHandler(systemTimerElapsed);
      }
      
      protected void systemTimerElapsed(object sender, ElapsedEventArgs e)
      {
      _systemTimer.Stop();
      //Do what you need to do
      _systemTimer.Start();
      //This way if it takes longer than a second it won't matter, another time won't kick off until the previous job is done 
      }
      

      【讨论】:

        【解决方案5】:

        我会让你很容易;在另一个后台线程中使用 Thread.Sleep() 就完成了!

        如果您知道什么时候完成,而不仅仅是使用 AutoResetEvent 来保持线程同步。 如果你对更新无回调没有任何控制,时间不详建议增加你的定时器间隔!

        var thread = new Thread((ThreadStart)delegate
                {
                 While(true)
                   {
                     TSM.ModelObjectEnumerator myEnum = null;
                     myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
                     while (myEnum.MoveNext())
                      {
                          if (myEnum.Current != null)
                         {....}
                      }
        
                      Thread.Sleep(1000);
                   }
                 }
            thread.Start();
        

        【讨论】:

          【解决方案6】:

          根据处理程序的名称,我假设您使用的是单线程System.Windows.Forms.Timer。这意味着Tick 事件将在前一个事件结束后触发。要中断循环,您必须在另一个线程中执行代码并使用退出条件。

          这是我通常的做法:

          private bool running;
          private bool restart;
          
          private void DoWork(object item)
          {
              running = true;    
              TSM.ModelObjectEnumerator myEnum = null;
              myEnum = new TSM.UI.ModelObjectSelector().GetSelectedObjects();
          
              while (myEnum.MoveNext() && !restart)
              {       
                  //do your stuff
                  if (myEnum.Current != null) {....}
              }
          
              if(restart)
              {
                  restart = false;
                  ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
              }
          }
          
          private void timer1_Tick(object sender, EventArgs e)
          {
              if (running)
                  restart = true;
              else            
                  ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));            
          }
          

          【讨论】:

            【解决方案7】:

            从 txtString 的字符串中获取每个字符,并使用 timerControl 逐个写入标签

            int g = 0;
            private void timerString_Tick(object sender, EventArgs e)
            {
                string a = txtString.Text;
                int em = txtString.TextLength;
                if (g < em)
                {
                    lblString.Text = lblString.Text + a[g];
                    g++;
                }
                else timerString.Stop();
            }
            

            来自

            private void btnStringStart_Click(object sender, EventArgs e)
            {
                timerString.Start();
                lblString.Text = "";
            }
            

            【讨论】:

              猜你喜欢
              • 2013-11-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-08-27
              • 1970-01-01
              相关资源
              最近更新 更多