UI 多執行緒處理 WPF 用 UI 多執行緒處理 WPF 大量渲染的解決方案
用 UI 多執行緒處理 WPF 大量渲染的解決方案
眾所周知, 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 操作,所以主視窗沒有被這個大量渲染影響到。
最後
這業務場景還有什麼有用的解決方案,請留言教教我!
覺得對你有幫助點個推薦或者留言交流一下唄!
原始碼 https://github.com/yijidao/blog/tree/master/WPF/Multithread
WPF 執行緒模型文件 https://docs.microsoft.com/en-us/dotnet/desktop/wpf/advanced/threading-model?redirectedfrom=MSDN&view=netframeworkdesktop-4.8
眾所周知, 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 操作,所以主視窗沒有被這個大量渲染影響到。