2009-12-16 64 views
1

我在WPF線程有問題。我想創建一個複雜的用戶界面,然後我想將它添加到我的主窗口。雖然這個複雜的用戶界面正在創建,我想在我的主窗口中顯示進度條。我認爲這隻能用線程來完成。但有一個問題。創建的元素不能添加到主窗口,因爲它是在單獨的線程中創建的。 有誰知道是否有可能將在後臺線程中創建的UIElements傳輸到主線程。 如果我嘗試一種簡單的方式,它說該對象無法訪問,因爲它在一個單獨的線程。我已經使我的進度條線程安全。在後臺創建元素線程然後添加到主界面

我希望下面的例子更好地解釋我想要的東西。

StackPanel tcForm = new StackPanel(); 
Semaphore loadedSema = new Semaphore(0,1); 
Thread thread = new Thread(new ThreadStart(delegate(){ 
      //Formular should be created in background    
      tcForm.Children.Add(new Formular()); 
      ProgressBar.AddProgress(); 
      //...other things 
      loadedSema.Release(); 
})); 
thread.start(); 
loadedSema.WaitOne(); 

new Formular()運行很長時間,所以我想到了在後臺創建。

也不可能將Formular添加到變量中,然後將其添加到主線程中。

//this is also impossible 

//in background-thread 
form = new Formular 

//in main-thread 
tcForm.Children.Add(form); 

我希望有一種方法可以做到這一點。 將是很好,如果有一些建議,

謝謝,馬丁

回答

3

您應該使用Dispatcher.Invoke方法

... 
     this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(new Formular()); 
      ProgressBar.AddProgress();};) 
.... 

編輯
可以調度之前創建Fromular()對象,如果長時間工作

var f = new Formular(); 
this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(f); 
       ProgressBar.AddProgress();};) 
1

如果你想要做的是更新進度條(或類似),那麼你應該在主線程創建所有的UI前面和然後使用從後臺線程狀態更新發送到主線程形式的Invoke method(如發送int說0和100%之間的進度)

我不認爲有共享窗口之間形成控制的方式線程。

編輯:好吧,我現在看到,這是標記爲WPF。答案保持不變,但不是在控件上調用,而是使用Dispatcher類(每個圖形元素都包含對正確調度程序的引用)。您也可以使用另一個答案中建議的BackgroundWorker類。

+0

這是目前的工作方式。但是,如果使用這種方式,問題是進度條必須位於另一個窗口中。而且這個窗口不能是主窗口的子窗口。 – martin 2009-12-16 12:26:49

1

我對WPF瞭解不多,但是我剛剛瞭解到BackGroundWorker會爲你做好工作。

http://dotnetperls.com/backgroundworker

你只需要處理該任務後提出,應在主線程中運行WorkerCompleted事件。它還可以報告更新進度條的進度。

例子:

void worker_Start() 
    { 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += 
      new DoWorkEventHandler(worker_DoWork); 
     worker.RunWorkerCompleted += 
      new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 

     worker.RunWorkerAsync("MyArg"); 

    } 

    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     e.Result = new Formular(); 
    } 

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     this.Controls.Add((Control)e.Result); 
    } 
+0

如果我使用後臺工作者,我會遇到同樣的問題,就像我使用線程一樣。這是可以理解的,因爲backgroundworker也是一個線程。線程背景工作者之間的區別在於backgroundworker是線程池中的現有線程 – martin 2009-12-16 11:39:43

+0

如果在主線程中創建BackgroundWorker並附加到WorkerCompleted事件,則應該在主線程中執行此事件處理程序中的代碼(至少爲我工作)。我添加了一個例子。 – 2009-12-16 12:39:12

0

不 - 這不可能。 WPF主要是單線程的。

但是,您應該想知道爲什麼界面的創建需要很長時間。 WPF非常快。 「普通」控制的創建不應該是一個瓶頸。

也許你可以優化其他對象創作;嘗試分析你的應用程序。

並嘗試從下往上構建UI:最後一個操作應該是將控件添加到窗體。

0

你可以XAML序列化你的UI元素,然後將它們發送回主線程。不知道在主線程中反序列化是否比在第一個地方創建它們更快。

相關問題