用 UI 多執行緒處理 WPF 大量渲染的解決方案

鵝群中的鴨霸發表於2022-03-04

眾所周知, 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

相關文章