眾所周知, WPF 的 UI 渲染是單執行緒的,所以如果我們非同步或者新建執行緒去進行資料處理的時候,處理完,想要更新 UI 的時候,需要呼叫一下 Dispatcher.Invoke,將處理完的資料推入到 Dispatcher 中,等待更新介面,不然就會報呼叫執行緒無法訪問此物件,因為另一個執行緒擁有該物件的錯誤。
這就是為什麼 WPF 中的大多數物件派生自 DispatcherObject,因為需要 Dispatcher 處理併發和執行緒的情況。
但是工作中,有時候會遇到 UI 密集型的情況,也就是介面不停渲染導致介面出現卡住的情況,這時候就是 Dispatcher 忙不過來了,一般這時候,都會想要用多執行緒來渲染介面,但是一個 Dispatcher 只能為一個執行緒服務,所以我一般會將這種 UI 密集型的介面,單獨放到一個彈窗中,再新建一個 UI 執行緒並指定 Dispatcher 來渲染。
樣例程式碼
程式碼也很簡單,我直接貼啦!
我在介面中放了兩個按鈕,一個用來開啟負責大量渲染的視窗,一個用來關閉該視窗。
Window w = null;
newWindowButton.Click += (sender, args) =>
{
var thread = new Thread(() =>
{
w = new Window
{
Content = new LargeRenderView(),
Width = 1200,
Height = 1000
};
w.Show();
Dispatcher.Run(); // 執行 Dispatcher,為新建的 UI 執行緒服務
});
thread.SetApartmentState(ApartmentState.STA); // // 指定執行緒為單執行緒模式
thread.Start();
};
closeWindowButton.Click += (sender, args) =>
{
w.Close();
if (w == null) return;
if (w.Dispatcher.CheckAccess())
w.Close();
else
w.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(w.Close));
};
效果
可以看到新彈窗因為大量渲染,滑鼠一直在轉圈,無法操作,但是主視窗還是可以進行 UI 操作,所以主視窗沒有被這個大量渲染影響到。