How to use a timer to wait?

后端 未结 4 1167
名媛妹妹
名媛妹妹 2021-01-02 01:45

I am trying to delay events in my method by using a timer, however i do not necessarily understand how to use a timer to wait.

I set up my timer to be 2 seconds, but

相关标签:
4条回答
  • 2021-01-02 01:46

    If you're using C# 5.0 await makes this much easier:

    private async void button1_Click(object sender, EventArgs e)
    {
        label1.Text = "first";
        await Task.Delay(2000);
        label1.Text = "second";
    }
    
    0 讨论(0)
  • 2021-01-02 01:52
           private bool Delay(int millisecond)       
           {
    
               Stopwatch sw = new Stopwatch();
               sw.Start();
               bool flag = false;
               while (!flag)
               {
                   if (sw.ElapsedMilliseconds > millisecond) 
                   {
                      flag = true;
                   }
               }
               sw.Stop();
               return true;
    
           }
    
            bool del = Delay(1000);
    
    0 讨论(0)
  • 2021-01-02 01:55

    If all you're trying to do is change the text when the timer ticks, would you not be better off putting...

    label1.Text = "second";
    

    ...In the timer tick, either before or after you change the timer to enabled = false;

    Like so;

    void timer_Tick(object sender, EventArgs e)
    {
      timer.Stop();
      label1.Text = "second";
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
      label1.Text = "first";
      timer.Start();
    }
    
    0 讨论(0)
  • 2021-01-02 02:07

    timer.Start() just starts the timer but immediately returns while the timer is running in the background. So between setting the label text to first and to second there is nearly no pause. What you want to do is wait for the timer to tick and only then update the label again:

    void timer_Tick(object sender, EventArgs e)
    {
        timer.Stop();
        label1.Text = "second";
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        label1.Text = "first";
        timer.Start();
    }
    

    Btw. you should not set timer.Enabled to true, you are already starting the timer using timer.Start().

    As mentioned in the comments, you could put the timer creation into a method, like this (note: this is untested):

    public void Delayed(int delay, Action action)
    {
        Timer timer = new Timer();
        timer.Interval = delay;
        timer.Tick += (s, e) => {
            action();
            timer.Stop();
        };
        timer.Start();
    }
    

    And then you could just use it like this:

    private void button1_Click(object sender, EventArgs e)
    {
        label1.Text = "first";
        Delayed(2000, () => label1.Text = "second");
    }
    

    Tergiver’s follow-up

    Does using Delayed contain a memory leak (reference leak)?

    Subscribing to an event always creates a two-way reference.

    In this case timer.Tick gets a reference to an anonymous function (lambda). That function lifts a local variable timer, though it's a reference, not a value, and contains a reference to the passed in Action delegate. That delegate is going to contain a reference to label1, an instance member of the Form. So is there a circular reference from the Timer to the Form?

    I don't know the answer, I'm finding it a bit difficult to reason about. Because I don't know, I would remove the use of the lambda in Delayed, making it a proper method and having it, in addition to stopping the timer (which is the sender parameter of the method), also remove the event.

    Usually lambdas do not cause problems for the garbage collection. In this case, the timer instance only exists locally and the reference in the lambda does not prevent the garbage collection to collect the instances (see also this question).

    I actually tested this again using the .NET Memory Profiler. The timer objects were collected just fine, and no leaking happened. The profiler did give me a warning that there are instances that “[…] have been garbage collected without being properly disposed” though. Removing the event handler in itself (by keeping a reference to it) did not fix that though. Changing the captured timer reference to (Timer)s did not change that either.

    What did help—obviously—was to call a timer.Dispose() in the event handler after stopping the timer, but I’d argue if that is actually necessary. I don’t think the profiler warning/note is that critical.

    0 讨论(0)
提交回复
热议问题