2011-03-22 44 views
8

一個WPF應用程序具有從使用XamlReader.Load()方法的單獨的文件中加載用戶控制的操作:XamlReader.Load在後臺線程。可能嗎?

StreamReader mysr = new StreamReader(pathToFile); 
DependencyObject rootObject = XamlReader.Load(mysr.BaseStream) as DependencyObject; 
ContentControl displayPage = FindName("displayContentControl") as ContentControl; 
displayPage.Content = rootObject; 

的過程需要一段時間,由於文件的大小,所以UI變爲凍結幾秒鐘。

爲了保持應用程序響應我嘗試使用一個後臺線程執行不直接在UI更新involed操作的一部分。

當嘗試使用BackgroundWorker我得到了一個錯誤:調用線程必須爲STA,因爲許多UI組件都需要這個

所以,我走了另一條途徑:

private Thread _backgroundThread; 
_backgroundThread = new Thread(DoReadFile); 
_backgroundThread.SetApartmentState(ApartmentState.STA); 
_backgroundThread.Start(); 
void DoReadFile() 
{ 
    StreamReader mysr3 = new StreamReader(path2); 
    Dispatcher.BeginInvoke(
      DispatcherPriority.Normal, 
      (Action<StreamReader>)FinishedReading, 
      mysr3); 
} 

void FinishedReading(StreamReader stream) 
    {    
     DependencyObject rootObject = XamlReader.Load(stream.BaseStream) as DependencyObject; 
     ContentControl displayPage = FindName("displayContentControl") as ContentControl; 
     displayPage.Content = rootObject; 
    } 

這因爲所有耗時的操作都留在UI線程中,所以什麼都不解決。

當我嘗試這樣的,使所有在後臺解析:

private Thread _backgroundThread; 
_backgroundThread = new Thread(DoReadFile); 
_backgroundThread.SetApartmentState(ApartmentState.STA); 
_backgroundThread.Start(); 
void DoReadFile() 
{ 
    StreamReader mysr3 = new StreamReader(path2);  
    DependencyObject rootObject3 = XamlReader.Load(mysr3.BaseStream) as DependencyObject; 
     Dispatcher.BeginInvoke(
      DispatcherPriority.Normal, 
      (Action<DependencyObject>)FinishedReading, 
      rootObject3); 
    } 

    void FinishedReading(DependencyObject rootObject) 
    {    
    ContentControl displayPage = FindName("displayContentControl") as ContentControl; 
    displayPage.Content = rootObject; 
    } 

我有一個例外:,因爲不同的線程擁有它調用線程不能訪問該對象。(在加載的用戶控件有其他控制本這可能得到錯誤)

是否有任何的方式來以這樣的方式執行該操作的用戶界面以響應?

+0

使用BackgroundWorker的,確保如果你要修改(套/加)任何不在範圍內,而不是線程對象的BackgroundWorker的是您使用FUNC /動作或委派工作出來,不要試圖將其設置在BackgroundWorker的線程。如果有什麼做你的工作,而不是BackgroundWorker的,當你完成拍攝效果(e.result)中的onComplete事件/方法,並更新UI線程的對象。 – Landern 2011-03-22 17:26:19

回答

7

獲取XAML加載一個後臺線程本質上是一種非首發。 WPF組件具有線程相關性,並且通常只能從它們創建的線程中使用。因此,加載到後臺線程將使UI響應,但創建組件,然後無法插入UI線程。

你們這裏最好的辦法是到XAML文件分解成更小的碎片,並逐步加載它們在UI線程並確保允許在每個負荷運行之間的消息泵。可能使用Dispatcher對象BeginInvoke調度負載。

2

正如你發現的那樣,除非線程是STA,否則你不能使用XamlReader.Load,即使它是,你也必須讓它啓動一個消息泵,並通過它創建對它創建的控件的所有訪問。這是WPF如何工作的基本方法,您不能違背它。

所以你唯一的真正的選擇是:

  1. 打破XAML成小塊。
  2. 啓動一個新的STA線程每個Load通話。之後Load返回後,線程將需要啓動一個消息循環,並管理它創建的控件。您的應用程序必須考慮到不同控件現在由不同線程擁有的事實。
0

系統。 XAML有Xaml​Background​Reader類,也許你能得到那個爲你工作。解析器的XAML在後臺線程,但建立在UI線程上的對象。