最近筆者調試修改項目,碰到了c#在work線程中怎樣更新UI控件中的場景,簡單總結了下,主要有兩個方法:
方法1:通過System.Windows.Application.Current.Dispatcher.Invoke來更新UI控件
System.Windows.Application.Current.Dispatcher.Invoke(() =>{ConnectCheckBox.IsChecked = false;});
方法2:通過SynchronizationContext實現,具體細節如下:
SynchronizationContext.Post?函數:主要用于在 Windows Forms 或者 WPF 等 UI 相關的應用程序中,以異步的方式將一個委托(在這里是?SetTextSafePost?方法)投遞到指定的同步上下文(m_SyncContext)中執行,下面詳細展開解釋其作用和原理。
1. 同步上下文(SynchronizationContext)的概念
在 Windows Forms 或者 WPF 應用程序中,UI 控件(如?ListView、TextBox?等)是線程不安全的,這意味著只有創建這些控件的線程(通常是主線程,也就是 UI 線程)才能夠訪問和修改它們。如果在其他線程中直接訪問和修改 UI 控件,會拋出?InvalidOperationException?異常。
SynchronizationContext?類提供了一種機制,允許在不同線程之間安全地切換執行上下文,確保在訪問 UI 控件時是在 UI 線程中進行的。在 Windows Forms 應用程序中,SynchronizationContext.Current?會返回當前線程的同步上下文,對于 UI 線程來說,這個同步上下文會確保委托在 UI 線程中執行。
2.?m_SyncContext.Post?方法的作用
m_SyncContext.Post?方法用于將一個委托異步投遞到指定的同步上下文中執行。它接受兩個參數:
- 第一個參數是一個?
SendOrPostCallback?委托,這個委托指向要執行的方法(在這里是?SetTextSafePost?方法)。 - 第二個參數是傳遞給委托方法的參數(在這里是?
lvi,即?ListViewItem?對象)。
Post?方法會將委托放入同步上下文的消息隊列中,然后立即返回,不會等待委托執行完成。同步上下文會在合適的時機(通常是 UI 線程處理消息隊列時)從消息隊列中取出委托并在 UI 線程中執行。
private void SetTextSafePost(object lvi)
{if (AlarmabsListView.Items.Count > 100){AlarmabsListView.Items.RemoveAt(100);}ListViewItem temp = lvi as ListViewItem;AlarmabsListView.Items.Insert(0, temp);
}private static SynchronizationContext m_SyncContext = null;// 在某個地方初始化同步上下文,通常在 UI 線程中進行
m_SyncContext = SynchronizationContext.Current;// ...if (strJson.ToLower().Contains("\"testInfo\""))
{ ListViewItem lvi = new ListViewItem();lvi.Text = heartBeat.EventNotificationAlert.dataTime;lvi.SubItems.Add(heartBeat.EventNotificationAlert.eventType);lvi.SubItems.Add(strJson);m_SyncContext.Post(SetTextSafePost, lvi);
}
4. 與?Send?方法的區別
SynchronizationContext?類還有一個?Send?方法,它與?Post?方法的區別在于:
Post?方法是異步的,它會將委托放入消息隊列中,然后立即返回,不會等待委托執行完成。Send?方法是同步的,它會等待委托執行完成后才返回。
在處理 UI 控件時,通常建議使用?Post?方法,以避免阻塞當前線程。