2011-03-22 45 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线程上的对象。