2014-10-10 110 views
2

我有以下應用程序結構中:更新UI線程

public partial class MainWindow : Window 
{ 
    // Methos to update the TextBlock 
    public void updateTextBlock(string txt) 
    { 
     this.myTextBlock.Text += txt; 
    }   

    private void startThreadBtn_Click(object sender, RoutedEventArgs e) 
    { 
     // Start Thread1 here 
     Thread1 thread1 = new Thread1(); 
     new Thread(new ThreadStart(thread1.doSomthing)).Start(); 
    } 
} 

class Thread1 
{ 
    public void doSomthing() 
    { 
     // ------------------------------ 
     // Update myTextBlock from here 
     // ------------------------------ 

     // Thread2 starts here 
     Thread2 thread2 = new Thread2(); 
     new Thread(new ThreadStart(thread2.doSomthing)).Start(); 
    } 
} 

class Thread2 
{ 
    public void doSomthing() 
    { 
     // ------------------------------ 
     // Update myTextBlock from here 
     // ------------------------------ 
    } 
} 

從這兩個線程Thread1Thread2類的我想更新TextBlock這是在MainWindow

我已經看到下面的解決方案,並沒有發現這個問題涵蓋在這個問題中,我也是初學者,發現它很難理解。

我可以使用在Thread1有關從Thread2更新UI上述問題,但什麼提供的解決方案。
我正在使用.NET框架4.5。
做什麼是最好的方法。

+1

這絕對是一樣的。 – Sinatr 2014-10-10 06:53:59

+0

您可否指出解決方案。 – User7723337 2014-10-10 06:54:44

+0

由於您在Window類中,因此可以使用Dispatcher。就像if(!Dispatcher.CheckAccess()){Dispatcher.BeingInvoker(...); }。不過,我會建議你看看TPL(任務並行庫)來啓動你的線程。由於您可以輕鬆地將任務鏈接在一起,並且使用SynchronizationContext在前景(UI)和後臺線程之間來回切換上下文,所以對於您所做的事情要好得多。 – kha 2014-10-10 06:57:54

回答

3

...一個線程中的線程...

看來,你有一些誤解什麼線程。讓我們看看這些:

  • 線程不會在另一個「內」執行。它們不是嵌套的。將線程視爲「並行」執行更爲準確。

    無論你如何以及從哪裏開始第二個線程。它只是一個線程,就像你的第一個線程一樣,所以當你想從這些(非UI)線程中更新UI時,在兩種情況下你都會做同樣的事情:在UI線程上調度你的UI更新代碼,這是在WPF中通過Dispatcher.InvokeDispatcher.InvokeAsync方法完成的。

    myTextBlock.Dispatcher.Invoke(() => { … /* update myTextBlock here */ }); 
    //         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    //       this will be scheduled on the correct (UI) thread 
    

    參見:How do I get the UI thread Dispatcher?

  • 線程是不一樣的你Thread1Thread2對象。將線程想象成代表通過代碼的執行路徑;或者如果您願意,可以自行執行的方法。一個線程有一個入口點(一個方法,由一個ThreadStart委託表示),它是開始執行的地方,當線程到達該線程的末尾時線程終止。

    class Thread1 
    { 
        … void doSomthing() 
        { 
         … 
         Thread2 thread2 = new Thread2(); 
         new Thread(new ThreadStart(thread2.doSomthing)).Start(); 
        } 
    } 
    

    即使你命名你的類Thread1Thread2,這並不能讓他們線程。它們是常規的.NET類,恰巧包含用作線程入口點的方法。線程僅由Thread類表示(並且請注意,您的類不能,也不能從Thread繼承)。再次,無論你在哪裏遇到.Start()他們;他們彼此獨立。

  • 當你有這樣的事情:

    class A { … } 
    class B { void Foo() { var a = new A(); … } 
    

    B只需要在何時何地的A實例被創建的一部分,但它並不能決定「其中」 A 。 (無論如何,課程實際上沒有位置。)因此,說「AB」內是錯誤的。 (類型A稱爲通過B的方法,以及a指得到的的B實例方法執行期間創建對象實例,但它仍然是從B完全獨立的。)


更新:關於下方的問題補充有關如何使myTextBlock知道你的線程,有兩種解決方案:

  1. 要麼將​​doSomthing方法移動到MainWindow類(並給它們唯一的名稱)。

  2. 通行證myTextBlockThread1Thread2對象:

    class Thread1 
    { 
        public Thread1(TextBlock textBlockToBeUpdated) 
        { 
         this.textBlock = textBlock; 
        } 
    
        private readonly TextBlock textBlock; 
    
        void doSomthing() 
        { 
         textBlock.Dispatcher.Invoke(() => { /* update textBlock here */ }); 
        } 
    } 
    
    … 
    
    class MainWindow 
    { 
        … void startThreadBtn_Click(…) 
        { 
         Thread1 thread1 = new Thread1(myTextBlock); // <-- 
         … 
        } 
    } 
    
+0

您可能還想解釋UI線程是如何以及爲何不同的,以及爲什麼「無法」處理來自非UI線程的UI控件。 – Luaan 2014-10-10 07:44:44

+0

'InvokeAsync'比'BeginInvoke'好。 – Sinatr 2014-10-10 07:46:09

+0

@Luaan:我可以,但那會回答一個不同的問題。 – stakx 2014-10-10 07:46:46