Search code examples
c#winformstimerbackgroundworkerfreeze

Windows Form freezes while timer tick


I have a problem, that my GUI is freezed while the timer ticks.

What should my Programm do: Read every 30 seconds my serialPort, save the data from the serialPort in a textfile and display the data on my windows Form. Everything is working but, everytime the timer ticks my GUI freeze for 4-5 seconds.

Here my Code:(Visual C#)

-startButton(){...}
-RefreshComports(){...}
-stopButton(){...}



    private void timer1_Tick(object sender, EventArgs e)
    {
      myFile = new StreamWriter(path, true);
      serialPort1.NewLine = "\r";

      if (serialPort1.IsOpen == false)
      {
        serialPort1.Open();
      }
          data = serialPort1.ReadLine(); 

           myFile.WriteLine(data);

           if (data.Contains(':'))
           {
              String tmp[] = data.Split(':');
              textBox1.Text = tmp[1];
              textBox2.Text = tmo[2];
            }
            serialPort1.Close();
            myFile.Flush();
            myFile.Close();
}

I tried to do this with an backgroundworke instead of timer but then I can't update my textboxes. Anyone could help me?


Solution

  • Timer.Tick event handler is executed on UI thread. I.e. main thread of your application. This thread is responsible for drawing your application on screen. Running event handler on UI thread allows you to use any UI controls in this handler, but any long-running operation in Tick event handler will freeze your application, because UI will not be drawn at that time.

    You should use System.Threading.Timer instead. It's callback is executed in background thread. Application will use main thread for drawing UI, and you will read data from port in other thread.

    timer = new System.Threading.Timer(_ => CheckPort(), null, 0, 30000);
    

    Your callback method:

        private void CheckPort()
        {
            serialPort1.NewLine = "\r";
            if (!serialPort1.IsOpen)
                serialPort1.Open();
    
            var data = serialPort1.ReadLine();
    
            using (var writer = new StreamWriter(path, true))
                writer.WriteLine(data);
    
            if (data.Contains(':'))
            {
                var parts = data.Split(':');
                Invoke((MethodInvoker)(() => DisplayData(parts[0], parts[1])));
            }
    
            serialPort1.Close();
        }
    
        private void DisplayData(string foo, string bar)
        {
            textBox1.Text = foo;
            textBox2.Text = bar;
        }
    

    Note that you need to invoke method which uses UI controls. Because it's not allowed to use controls from thread other than main thread.

    If you don't need to execute some operation periodically, then use BackgroundWorker component to run operations in background thread.