WPF頻繁更新UI卡頓問題

孤沉發表於2024-06-23

我的WPF程式,需要連線PLC、CCD、RFID、掃碼槍、控制卡
所以我寫了

  InitHardware();
 private void InitHardware()
 {
     var tasks = new Task[]
     {
         //後臺執行緒長連線,不取消令牌
         Task.Factory.StartNew(() => InitConnPLC(),CancellationToken.None,TaskCreationOptions.LongRunning,TaskScheduler.Default),
         Task.Factory.StartNew(() => InitConnRFId(),CancellationToken.None,TaskCreationOptions.LongRunning,TaskScheduler.Default),
         Task.Factory.StartNew(() => InitConnCCd(),CancellationToken.None,TaskCreationOptions.LongRunning,TaskScheduler.Default),
         Task.Factory.StartNew(() => InitScanCode(),CancellationToken.None,TaskCreationOptions.LongRunning,TaskScheduler.Default),
         Task.Factory.StartNew(() => InitControlCard(),CancellationToken.None,TaskCreationOptions.LongRunning,TaskScheduler.Default),
     };
     Task.Factory.ContinueWhenAll(tasks, completedTasks =>
     {
         // 當所有任務完成時的邏輯
         foreach (var task in completedTasks)
         {
             if (task.IsFaulted)
             {
                 // 處理任務異常
                 Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
                 {
                     HandyOrgMessageBox.Info("Task。PLC連線失敗");                      //這段程式碼先放著,我在其他地方做了異常處理
                 }));
             }
             // 其他所有任務完成時的邏輯
         }
     });
 }
 
  /// <summary>
 /// 初始化PLC,為了應對不同公司的風格
 /// PLC讀取Ini檔案
 /// </summary>
 public void InitConnPLC()
 {
     PlcClient.Current.PlcCount = SysPlc.PlcCount = IniHelper.Current.GetPath("Config/setting.ini").GetSection("PlcCount").ToInt();
     PlcClient.Current.DefaultPlc = ObPLC.Where(it => it.IP == IPHelper.LocalIP4FromPLC).First(); //如果一個PLC走這條線,用於前期測試,正式釋出可以不寫DefaultPlc,會自動跟據PlcCount的多少連線
     PlcClient.Current.FindRuningPlc = ObPLC.ToArray(); //如果多個PLC走這條線

     while (true)
     {
         Task.Delay(200);
         Dispatcher.CurrentDispatcher.Invoke(
               new Action(() =>
               {
                   PlcInfo.IsConn = result.IsSuccess;
                   PlcInfo.PlcName = PlcInfo.IsConn ? "已連線PLC" : "未連線PLC";
               })
           );
     }
   
 }

可以看出我在這5個類似的方法中頻繁更新UI,因為我要和裝置長連線
解決方案1、將更新UI從while中剔除出來,寫在UI執行緒
首先增加一個靜態的全域性變數

public class SysPlc
{
	public static bool IsConn {get;set;}
}

那麼 Dispatcher.CurrentDispatcher.Invoke不必頻繁去寫。
修改while

  while (true)
  {
      Task.Delay(200);
      var result = PlcClient.Current.ConnectionPLC;
      SysPlc.IsConn  = result.IsSuccess;
  }

然後加入定時器

  _dispatcherTimer = new DispatcherTimer();
  _dispatcherTimer.Interval = TimeSpan.FromMilliseconds(500);
  _dispatcherTimer.Tick += OnTick;
  _dispatcherTimer.Start();

在UI執行緒透過全域性靜態傳遞過來的資料更新UI

  private void OnTick(object sender, EventArgs e)
  {
      PlcInfo.PlcName = SysPlc.IsConn ? "已連線PLC" : "未連線PLC";
  }

相關文章