2014-10-10 189 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