强制方法等待计时器在C#中停止

时间:2018-10-14 07:27:55

标签: c# timer

好的,我有一个模拟器,其中包含一些方法和一个计时器。我在这里启动计时器:

private void StartSimulation(object sender,EventArgs e)
{ 
    while(execList.Count != 0)
    {
        Assign(MF,Mpre);
        retCT = ChooseTransition(execList);
        ttoexec = retCT[1];
        this.time = retCT[0];                     
        timer.Start();
        // I need to stop execution of this method here untill timer stops ticking
        ExecuteTransition(ttoexec);
        execList.Remove(ttoexec);
    }
}

计时器方法类似于:

private void Timer_Tick(object sender,EventArgs e)
{
    --time;
    ++k;
    output.Add("t.u : " + k + "  " + "M = [" + MF.GetRowVal() + "];");
    if (time == 0)
    {
        timer.Stop();
    }
}

变量时间是int类型的,它包含需要计时的秒数(时间*计时器间隔时间的1000毫秒)。请注意,在StartSimulation方法中,我使用数组中的值设置时间。

更新

我正在使用System.Windows.Forms.Timer

我希望我的StartSimulation()停止执行直到计时器停止(直到timer.Stop()中的Timer_Tick执行)。输出是一个字符串列表,最后我将写一个txt文件。

现在的问题是StartSimulation()的执行与计时器的滴答声同时发生,因此输出列表只有1个元素(我在StartSimulation()代码开头插入了一个元素,没有粘贴到这里)。

因此,我打开txt文件,将其写入,然后将其关闭,计时器仍在运行。调用timer.Start()方法时,StartSimulation的执行应停止

3 个答案:

答案 0 :(得分:2)

您可以检查Enabled属性。

根据official documentation,通过将Elapsed设置为Enabled,停止引发false事件。

答案 1 :(得分:1)

好吧,我设法使其正常运行,如果有人需要实现类似的功能,它将在此处发布代码:

 private void Timer_Tick(object sender,EventArgs e)
    {
        --time;
        ++k;

        if (time == 0)
        {
            ExecuteTransition(ttoexec);
            output.Add($"t.u : {k} M = [{MF.GetRowVal()}];");
            timer.Stop();
        }
        else
        {
            output.Add($"t.u : {k} M = [{MF.GetRowVal()}];");
        }

    }
    private bool isDone()
    {
        while (true)
        {
            if (!timer.Enabled) return true;
        }
    }
    private Task DoAsync()
    {
        return Task.Factory.StartNew(() => isDone());
    }

  private async void StartSimulation(object sender,EventArgs e)
  {  
    ...
    await DoAsync(); // it won't go further unless method isDone() return anything
    ...
   }

答案 2 :(得分:0)

好的,无需过多重构代码,并保持问题的原始精神。

就像在UI线程上一样,一种解决方案是使用async await模式来保持UI响应,并使用AutoResetEvent。不幸的是,AutoResetEvent并不值得期待,但是您可以构建自己的

给出

public class AsyncAutoResetEvent
{
   private static readonly Task _completed = Task.FromResult(true);
   private readonly Queue<TaskCompletionSource<bool>> _waits = new Queue<TaskCompletionSource<bool>>();
   private bool _signaled;

   public Task WaitAsync()
   {
      lock (_waits)
      {
         if (_signaled)
         {
            _signaled = false;
            return _completed;
         }

         var tcs = new TaskCompletionSource<bool>();
         _waits.Enqueue(tcs);
         return tcs.Task;
      }
   }

   public void Set()
   {
      TaskCompletionSource<bool> toRelease = null;

      lock (_waits)
         if (_waits.Count > 0)
            toRelease = _waits.Dequeue();
         else if (!_signaled)
            _signaled = true;

      toRelease?.SetResult(true);
   }
}

用法

private AsyncAutoResetEvent asyncAutoResetEvent = new AsyncAutoResetEvent();

...

private async Task StartSimulation(object sender, EventArgs e)
{
   while (execList.Count != 0)
   {
      Assign(MF, Mpre);
      retCT = ChooseTransition(execList);
      ttoexec = retCT[1];
      this.time = retCT[0];
      timer.Start();

      // stop here and leaves the UI responsive
      // until its set again
      await AsyncAutoResetEvent.WaitAsync();

      ExecuteTransition(ttoexec);
      execList.Remove(ttoexec);
   }
}

private void Timer_Tick(object sender,EventArgs e)
{
    --time;
    ++k;
    output.Add("t.u : " + k + "  " + "M = [" + MF.GetRowVal() + "];");
    if (time == 0)
    {
        timer.Stop();
        AsyncAutoResetEvent.Set();
    }
}

注意 :使用此解决方案,您将需要通过代码向后传播async await < / p>

免责声明 :实际上,还有其他方法可以使用任务和大量不同的代码重组来完成您想做的事情,尽管这应该可行