0

I should refresh a 10 of controls on the Home page every 100ms. Right now I'm using the DispatcherTimer. The interface refreshes but occasionally some component gets stuck at the previous value. Here is the code I am using:

private void Timer_Tick(object? sender, EventArgs e)
    {
        try
        {
            var data = driver.GetData();
            if (data != null)
            {
                if (data.Krd3Front.TempOk)
                {
                    TxtTempFront1.Foreground = Brushes.Lime;
                    TxtPvTempBarFront.Foreground = Brushes.Lime;
                    TxtTempFront2.Foreground = Brushes.Lime;
                }
                else
                {
                    TxtTempFront1.Foreground = Brushes.Red;
                    TxtPvTempBarFront.Foreground = Brushes.Red;
                    TxtTempFront2.Foreground = Brushes.Red;
                }
                if (data.Krd3Rear.TempOk)
                {
                    TxtTempRear1.Foreground = Brushes.Lime;
                    TxtPvTempBarRear.Foreground = Brushes.Lime;
                    TxtTempRear2.Foreground = Brushes.Lime;
                }
                else
                {
                    TxtTempRear1.Foreground = Brushes.Red;
                    TxtPvTempBarRear.Foreground = Brushes.Red;
                    TxtTempRear2.Foreground = Brushes.Red;
                }
                TxtPvTempBarFront.Text = data.Krd3Front.Pv.ToString();
                TxtPvTempBarRear.Text = data.Krd3Rear.Pv.ToString();
                ProgressBarFront.Progress = data.Krd3Front.Pv;
                ProgressBarRear.Progress = data.Krd3Rear.Pv;
                ProgresVacuum.Progress = data.AsblyLine.FdbkVacuum;
                ProgresGas.Progress = data.AsblyLine.FdbkGas;
                ProgresSealing.Progress = data.AsblyLine.FdbkSealing;
                TxtActVacuum.Text = data.AsblyLine.FdbkActVacuum.ToString();
                TxtActGas.Text = data.AsblyLine.FdbkActGas.ToString();
                TxtActSealing.Text = data.AsblyLine.FdbkActSealing.ToString();
            }
        }
        catch (Exception ex)
        {
            App.logger.Error(ex.Message);
        }

I think it's not the correct way to update the UI in this case. Can you give me some advice on this?

I expected the DispatcherTimer to be the solution to my problem.

  • You should look into Viewmodel Binding that would be the correct way to update WPF. You can also probably use a background thread to fetch the data, then call a method to update the viewmodel and trigger the NotifyPropertyChanged handlers. I recommend looking up the community toolkit to see useful ways of handling UI binding. – MiltoxBeyond Jul 04 '23 at 06:11
  • 1
    There is no single "*correct way*". Different approaches have different advantages and disadvantages. There is nothing wrong with the code you are showing here. You should however make sure that the `GetData()` call does not take a significant fraction of the timer interval. If it is a time-consuming task, consider an `async` approach. – Clemens Jul 04 '23 at 06:50
  • If I make the GetData() method async, what if it doesn't complete the operations in the GetData() method in time and another Tick wind comes? – Maintenance Jul 04 '23 at 07:10
  • If you use system Timer, you'll need to call `App.Dispatcher.BeginInvoke` in order to update the UI and that would be safe because the UI code inside the delegate won't be running in parallel, but GetData must be thread safe – yassinMi Jul 04 '23 at 07:24
  • Alternatively you can start a dedicated background thread with a loop where you call `Thread.Sleep(ms)`, `GetData` then `BeginInvoke` this will allow you to regulate the frequency however you want – yassinMi Jul 04 '23 at 07:28
  • I'd love to get some code examples, I'm fairly new to .NET programming, I don't want to use the MVVM pattern yet. The async GetData() method should I use without await? – Maintenance Jul 04 '23 at 08:02
  • If GetData is declared `async` it must be awaited. The Tick handler method must also be declared `async`. If you can not make sure that GetData takes less time than the timer interval, you may alternatively run an infinite async loop with `await Task.Delay(...)`. – Clemens Jul 04 '23 at 09:21
  • @Maintenance: If "component gets stuck at the previous value", maybe you should increase the interval to like 250ms or more? – mm8 Jul 04 '23 at 13:04
  • What happens if I create the GetDataAsync() method as async and call it in the Dispatcher Timer with await. What happens if the Timer starts and the processing is not finished? I expect that being in separate thread (GetDataAsync) the framework takes me back to the await even if I passed Tick. I hope I made myself clear – Maintenance Jul 04 '23 at 14:25

0 Answers0