question

UyenNguyen-4262 avatar image
0 Votes"
UyenNguyen-4262 asked UyenNguyen-4262 commented

How to make a countdown Timer continue even when Winform is closed?

Hello. I'm new to windows form so I don't really understand how things work. Recently, I try to make a countdown timer that counts from a certain time to 0. But when the form is closed, everything is like "reset" and I don't want that. What I want is, for example, countdown time is 5 mins -> close form -> open form after 3 mins -> countdown time is 2 mins left. I wonder if you guys can share any ideas that will make it works and are simple so I can understand . Thanks in advance!

dotnet-csharpwindows-forms
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

JackJJun-MSFT avatar image
0 Votes"
JackJJun-MSFT answered UyenNguyen-4262 commented

@UyenNguyen-4262, Welcome to Microsoft Q&A, Based on your description, you want to make a countdown timer and hope that it will contine when the form is closed.

I make some steps and code example. You could check if it works for you.

First, I make a countdown Timer from the answer.

Second, I add the following settings in the winform.

200800-image.png

Third, I used FormClosing event to save some information to the settings.

   private void Form1_FormClosing(object sender, FormClosingEventArgs e)
         {
             if(timer.IsRunnign)
             {
                 Properties.Settings.Default.lefttime = label1.Text;
                 Properties.Settings.Default.Isrunning = true;
                 Properties.Settings.Default.closedtime=DateTime.Now;
                 Properties.Settings.Default.Save();
             }
         }
    
  Fourth, I used Form1_Load event to read the information.
    
   private void Form1_Load(object sender, EventArgs e)
         {
             if (Properties.Settings.Default.Isrunning== true)
             {
                 string lefttime = Properties.Settings.Default.lefttime;
                 TimeSpan time1=TimeSpan.ParseExact(lefttime, @"mm\:ss", CultureInfo.CurrentCulture);
                 DateTime closedtime = Properties.Settings.Default.closedtime;
                 TimeSpan passedtime = DateTime.Now - closedtime;
                 var t = time1.Subtract(passedtime);
                 label1.Text=t.ToString(@"mm\:ss");
                 timer.SetTime(t.Minutes, t.Seconds);
                 timer.Start();
                 timer.TimeChanged += () => { label1.Text = timer.TimeLeftStr; };
    
                 // show messageBox on timer = 00:00.000
                 timer.CountDownFinished += () => { timer.Stop(); MessageBox.Show("Timer finished the work!"); };
    
                 //timer step. By default is 1 second
                 timer.StepMs = 1; // for nice milliseconds time switch
             }
             else
             {
                 //set to 5 mins
                 timer.SetTime(5, 0);
    
                 //update label text
                 timer.TimeChanged += () => { label1.Text = timer.TimeLeftStr; };
    
                 // show messageBox on timer = 00:00.000
                 timer.CountDownFinished += () => { timer.Stop(); MessageBox.Show("Timer finished the work!"); };
    
                 //timer step. By default is 1 second
                 timer.StepMs = 1; // for nice milliseconds time switch
             }
               
         }

Finally, Please set the properties when we click the stop button.

Completed code:


  public partial class Form1 : Form
     {
         public Form1()
         {
             InitializeComponent();
         }
         CountDownTimer timer = new CountDownTimer();
         private void Form1_Load(object sender, EventArgs e)
         {
             if (Properties.Settings.Default.Isrunning== true)
             {
                 string lefttime = Properties.Settings.Default.lefttime;
                 TimeSpan time1=TimeSpan.ParseExact(lefttime, @"mm\:ss", CultureInfo.CurrentCulture);
                 DateTime closedtime = Properties.Settings.Default.closedtime;
                 TimeSpan passedtime = DateTime.Now - closedtime;
                 var t = time1.Subtract(passedtime);
                 label1.Text=t.ToString(@"mm\:ss");
                 timer.SetTime(t.Minutes, t.Seconds);
                 timer.Start();
                 timer.TimeChanged += () => { label1.Text = timer.TimeLeftStr; };
    
                 // show messageBox on timer = 00:00.000
                 timer.CountDownFinished += () => { timer.Stop(); MessageBox.Show("Timer finished the work!"); };
    
                 //timer step. By default is 1 second
                 timer.StepMs = 1; // for nice milliseconds time switch
             }
             else
             {
                 //set to 5 mins
                 timer.SetTime(5, 0);
    
                 //update label text
                 timer.TimeChanged += () => { label1.Text = timer.TimeLeftStr; };
    
                 // show messageBox on timer = 00:00.000
                 timer.CountDownFinished += () => { timer.Stop(); MessageBox.Show("Timer finished the work!"); };
    
                 //timer step. By default is 1 second
                 timer.StepMs = 1; // for nice milliseconds time switch
                 Console.WriteLine(Properties.Settings.Default.lefttime);
             }
               
         }
    
         private void button1_Click(object sender, EventArgs e)
         {
             timer.Start();
         }
    
         private void button2_Click(object sender, EventArgs e)
         {
             timer.Pause();
         }
    
         private void button3_Click(object sender, EventArgs e)
         {
             timer.Stop();
             timer.Dispose();
             Properties.Settings.Default.lefttime = "";
             Properties.Settings.Default.Isrunning = false;
             Properties.Settings.Default.closedtime = DateTime.Now;
             Properties.Settings.Default.Save();
         }
    
         private void Form1_FormClosing(object sender, FormClosingEventArgs e)
         {
             if(timer.IsRunnign)
             {
                 Properties.Settings.Default.lefttime = label1.Text;
                 Properties.Settings.Default.Isrunning = true;
                 Properties.Settings.Default.closedtime=DateTime.Now;
                 Properties.Settings.Default.Save();
             }
         }
     }
     public class CountDownTimer : IDisposable
     {
         public Stopwatch _stpWatch = new Stopwatch();
    
         public Action TimeChanged;
         public Action CountDownFinished;
    
         public bool IsRunnign => timer.Enabled;
    
         public int StepMs
         {
             get => timer.Interval;
             set => timer.Interval = value;
         }
    
         private Timer timer = new Timer();
    
         private TimeSpan _max = TimeSpan.FromMilliseconds(30000);
    
         public TimeSpan TimeLeft => (_max.TotalMilliseconds - _stpWatch.ElapsedMilliseconds) > 0 ? TimeSpan.FromMilliseconds(_max.TotalMilliseconds - _stpWatch.ElapsedMilliseconds) : TimeSpan.FromMilliseconds(0);
    
         private bool _mustStop => (_max.TotalMilliseconds - _stpWatch.ElapsedMilliseconds) < 0;
    
         public string TimeLeftStr => TimeLeft.ToString(@"mm\:ss");
    
         public string TimeLeftMsStr => TimeLeft.ToString(@"mm\:ss\.fff");
    
         private void TimerTick(object sender, EventArgs e)
         {
             TimeChanged?.Invoke();
    
             if (_mustStop)
             {
                 CountDownFinished?.Invoke();
                 _stpWatch.Stop();
                 timer.Enabled = false;
             }
         }
    
         public CountDownTimer(int min, int sec)
         {
             SetTime(min, sec);
             Init();
         }
    
         public CountDownTimer(TimeSpan ts)
         {
             SetTime(ts);
             Init();
         }
    
         public CountDownTimer()
         {
             Init();
         }
    
         private void Init()
         {
             StepMs = 1000;
             timer.Tick += new EventHandler(TimerTick);
         }
    
         public void SetTime(TimeSpan ts)
         {
             _max = ts;
             TimeChanged?.Invoke();
         }
    
         public void SetTime(int min, int sec = 0) => SetTime(TimeSpan.FromSeconds(min * 60 + sec));
    
         public void Start()
         {
             timer.Start();
             _stpWatch.Start();
         }
    
         public void Pause()
         {
             timer.Stop();
             _stpWatch.Stop();
         }
    
         public void Stop()
         {
             Reset();
             Pause();
         }
    
         public void Reset()
         {
             _stpWatch.Reset();
         }
    
         public void Restart()
         {
             _stpWatch.Reset();
             timer.Start();
         }
    
         public void Dispose() => timer.Dispose();
     }

Tested result:

200921-3.gif



Hope this could help you.

Best Regards,
Jack


If the answer is the right solution, please click "Accept Answer" and upvote it.If you have extra questions about this answer, please click "Comment".

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



image.png (16.4 KiB)
3.gif (288.8 KiB)
· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks, Jack!
Your code worked well, but after I add Form_Load and then Form_Closing events to the form, it started throwing this exception, I tried to edit something, but it still won't work again. Do you have any ideas about how to solve it?201150-2022-05-11.png


0 Votes 0 ·
2022-05-11.png (344.4 KiB)

@UyenNguyen-4262, thanks for the feedback, could you show me the value of lefttime?

0 Votes 0 ·

Ok so here is the value of lefttime (?), it contains nothing though. Well, after I restarted the winform, it refreshed and worked when I clicked button1(Start button) but something was wrong with the label text I think, it started with an "m" (??). I changed the ParseExact method to TryParseExact, so it won't throw an exception, however, the label wouldn't react when I clicked the buttons.201313-2022-05-11-2.png201296-2022-05-11-3.png


0 Votes 0 ·
2022-05-11-2.png (267.0 KiB)
2022-05-11-3.png (211.2 KiB)
Show more comments