Search code examples
multithreadingwinformstimerserial-port

Displaying countdown in multi threaded C# WIndows Forms app


I have tried several solutions with timers (tried all three timer classes) and none fire the Tick(elapsed) event in that specific spot. I have a multi-threaded WinForms application. What I need seems simple but I have spent days on this and ready to throw in the towel.

I need to display the live countdown in a pop up by second while an action is being executed. If 90 seconds pass with no results achieved (i have a flag), display warning, so I need to update the UI thread for sure.

I have looked into three different Timer classes and none work for me in that particular spot - their elapsed or tick events do not fire. I am thinking it's because I already have another thread that's polling the Serial Port because if I create a dummy button and tie the timer to the Click event, it's fine. Please note that I don't need the Timer to start inside the Serial Port polling, the functionality is totally separate.

Can someone suggest any solution that might work in this case?

Classes i tried are

 Windows.Forms.Timer
    System.Timers.Timer
    System.Threading.Timer

Solution

  • This answer assumes the "Popup" will not blocking the main UI Thread.

    Create new MIDI child Form for your "Popup" if you want it to exist within the confines of the parent form otherwise this works fine.

    Code taken from Alex's very helpful answer here: How to use a BackgroundWorker?

    public Popup()
    {
        InitializeComponent();
    
        backgroundWorker1.DoWork += backgroundWorker1_DoWork;
        backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
        backgroundWorker1.WorkerReportsProgress = true;
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();
    }
    
    private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(1000);
            backgroundWorker1.ReportProgress(i);
        }
    }
    
    private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        if(progressBar1.Value == 90) 
            WarningLbl.Text = "WARNING: Process is taking too long to complete.";
    }