簡體   English   中英

在后台線程中創建WPF組件

[英]Creating WPF components in background thread

進出口報告系統的工作,一系列DocumentPage是通過創建DocumentPaginator 這些文檔包括許多要實例化的WPF組件 ,因此分頁器在以后發送到XpsDocumentWriter (然后又發送到實際打印機)時包括正確的內容。

我現在的問題是,創建DocumentPage實例要花很長時間(Windows足以將應用程序標記為凍結),所以我嘗試在后台線程中創建它們,這是有問題的,因為WPF希望從中設置它們的屬性。 GUI線程。 我還希望顯示一個進度條,指示到目前為止已創建了多少個頁面。 因此,似乎Im試圖在GUI上並行發生兩件事。

這個問題很難解釋,我真的不確定如何解決。 簡而言之:

  • 創建一系列DocumentPag e。
    • 這些包括WPF組件
    • 這些將在后台線程上創建,或使用其他技巧使應用程序不凍結。
  • 創建每個頁面后,應更新WPF ProgressBar

如果沒有做到這一點的體面方法,則非常歡迎使用替代解決方案和方法。

只要線程是STA,您就應該能夠在后台線程中運行分頁器。

設置線程后,請在運行線程之前嘗試此操作。

thread.SetApartmentState(ApartmentState.STA);

如果確實必須使用GUI線程,請檢出Freezable類,因為您可能必須將對象從后台線程移至GUI線程。

在這個游戲上,游戲有點晚了,但是我只是為此解決了一個辦法,所以我想分享一下。 為了顯示UI元素,必須在將顯示它們的UI線程上創建它們。 由於長時間運行的任務在UI線程上,因此它將阻止進度條的更新。 為了解決這個問題,我在新的UI線程上創建了進度條,並在主UI線程上創建了頁面。

        Thread t = new Thread(() =>
            {
                ProgressDialog pd = new ProgressDialog(context);
                pd.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
                pd.Show();
                System.Windows.Threading.Dispatcher.Run();
            });
        t.SetApartmentState(ApartmentState.STA);
        t.IsBackground = true;
        t.Start();

        Action();   //we need to execute the action on the main thread so that UI elements created by the action can later be displayed in the main UI

“ ProgressDialog”是我自己的WPF窗口,用於顯示進度信息。

“上下文”保存我的進度對話框的進度數據。 它包括一個canceled屬性,以便我可以中止在主線程上運行的操作。 它還包括complete屬性,因此在Action完成后可以關閉進度對話框。

“操作”是用於創建所有UI元素的方法。 它監視取消標志的上下文,如果設置了標志,則停止生成UI元素。 完成時設置完成標志。

我不記得我必須將Thread't'設置為STA線程並將IsBackground設置為true的確切原因,但是我很確定如果沒有它們,它將無法正常工作。

如果需要UI線程的部分相對較小,則可以使用Dispatcher來執行那些操作,而不會阻塞UI。 與此相關的開銷很大,但它可能允許大部分計算在后台進行,並且會使UI線程上的工作與其他UI任務交錯。 您也可以使用分派器更新進度條。

我的猜測是,創建所有耗時的內容都在Visual中。 如果是這樣,那么有一個簡單的解決方案:在調用DocumentPaginator.GetPage()之前,不要創建實際的DocumentPage對象及其關聯的Visuals。

只要占用您文檔的代碼一次只請求一頁或兩頁,就不會出現性能瓶頸。

如果要打印到打印機或文件,則可以在后台線程上完成所有操作,但是如果要在屏幕上顯示,則無論如何一次只需要顯示幾個DocumentPages。 無論哪種情況,您都不會獲得任何UI鎖定。

最壞的情況是應用程序以縮略圖顯示頁面。 在這種情況下,我將:

  1. 縮略圖視圖會將其ItemsSource綁定到“ RealizedPages”集合,該集合最初填充有偽頁面
  2. 每當測量偽頁面時,它都會在DispatcherPriority.Background上將調度程序操作排隊,以調用DocumentPaginator.GetPage(),然后用實際頁面替換RealizedPages集合中的偽頁面。

如果由於單個項目的數量而導致即使在實現單個頁面時也存在性能問題,則可以頁面上具有大量項目的ItemsControl中使用這種相同的通用方法。

還有一點要注意:XPS打印系統一次不會處理一個以上的DocumentPage,因此,如果您知道那是您的客戶,則實際上可以通過適當的修改一遍又一遍地返回相同的DocumentPage。

更詳細地說明Ray Burns的答案:您是否可以在后台線程的類中完成數據處理,然后在處理完成后將DocumentPage的屬性數據綁定到此類?

暫無
暫無

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

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