簡體   English   中英

使用“async/await”時可以獲取 UI 線程上下文嗎

[英]Can I get UI thread context while using 'async/await'

我想知道在使用 Asyn/await 方法時是否可以獲取 UI 線程上下文。 如果是,如何?

使用 WPF/MVVM 模式編寫的代碼:

long asyncTimeChecker = 0;
int prevSec2 = 0;

/// <summary>
/// Button Click Command
/// </summary>
private void ExeTimerActivate(object o)
{
   if (!IsTimerStart)
   {
      ActivateAsyncTicToc();
      TimerState = "Stop";
   }
   else if (IsTimerStart)
   {
      ActivateAsyncTicToc();
      TimerState = "Start";
   }

   IsTimerStart = !IsTimerStart;
}        

/// <summary>
/// Call Method By Async/Await
/// </summary>
private async void ActivateAsyncTicToc()
{
  IsTimerStartAsync = !IsTimerStartAsync;

  var task1 = Task.Run(() => AsyncTicToc());
  await task1;
}



/// <summary>
/// I tried to UI access by other thread what use Async/Await
/// </summary>
private void AsyncTicToc()
{
  while (IsTimerStartAsync)
  {
      System.Threading.Thread.Sleep(10);
      AsyncTimeText = $"{asyncTimeChecker / 1000}.{asyncTimeChecker % 1000}";
      asyncTimeChecker += 10;

      /// ========================================
      /// This Position Get CrossThread Problem
      /// ========================================
      if (prevSec2 < asyncTimeChecker / 1000)
      {
           prevSec2++;
           if (TimerColor2.Color == Colors.Blue)
               TimerColor2.Color = Colors.Red;
           else
               TimerColor2.Color = Colors.Blue;
       }
   }

}

我知道我們可以使用 Dispatcher 獲取 UI 線程,但想知道是否可以使用 async/await。

您將async調用包裝在一個任務中。 這會破壞整個狀態機,並最終不必要地使用線程池線程。

調用和任何延續都會在另一個線程中結束,因此如果不進行編組就無法訪問 UI。

如果您絕對需要使用async void ,則至少應該這樣做 - 它只是在等待任務,而不是包裝它。

private async void ActivateAsyncTicToc()
{
   try
   {
      IsTimerStartAsync = !IsTimerStartAsync;    
      await AsyncTicToc();
   }
   catch (Exception e)
   {
      // make sure you observe exceptions in async void
   }
}

更好的是,讓async傳播使用async Task

private async Task ActivateAsyncTicToc()
{
   IsTimerStartAsync = !IsTimerStartAsync;    
   await AsyncTicToc();
}

無論如何,這看起來很可疑,您可能應該這樣做(省略asyncawait )並將任務傳遞給將要等待的其他人。 這是一個小的性能提升:

private Task ActivateAsyncTicToc()
{
   IsTimerStartAsync = !IsTimerStartAsync;    
   return AsyncTicToc();
}

事實上,這是一個雷區,我會在這里待一整天。

您需要開始閱讀有關asyncawait

首先,您可以使用await Task.Delay(10)而不是Thread.Sleep(10)並將您的AsyncTicToc方法更改為async Task而不啟動線程。 這將更改 UI 線程(您等待的上下文)中的控件。

其次,要從其他線程更新 UI,如果不想直接使用調度程序,可以使用它的抽象: SynchronizationContext類。 在此處查看更多信息。

示例: SynchronizationContext.Current.Post(action, actionParameter);

第三,使用視圖模型和綁定更合適。 如果您使用 WPF,它會為您同步線程以進行屬性更改。

雖然可以使用DispatcherSynchronizationContext從另一個線程“伸出”到 UI 線程,但我強烈建議不要這樣做。 這是因為它使您的邏輯更難測試並且更受其環境約束。 Dispatcher的情況下,它與在 WPF 環境中運行緊密相關; SynchronizationContext更好,但它仍然依賴於在某種環境中運行。

使用這種方法,您的邏輯與 UI 線程之間存在依賴關系,如下所示:

UI 代碼 => 后台線程邏輯 => UI 線程

相反,使用后台線程邏輯中的IProgress<T>Progress<T>將進度報告傳送回其調用方,后者決定如何顯示這些進度報告。 然后你的依賴看起來像這樣:

UI 代碼 => 后台線程邏輯

並且您的后台線程邏輯不依賴於存在的 UI 線程。 這使其更具可重用性和可測試性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM