从后台更新UI线程和线程内的线程

时间:2014-10-10 06:51:22

标签: c# wpf multithreading

我有以下应用程序结构:

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更新用户界面。
我正在使用.NET framework 4.5 这样做的最佳方式是什么。

1 个答案:

答案 0 :(得分:3)

  

...线程内的线程......

您似乎对线程有什么误解。让我们来看看这些:

  • 线程未执行"在"另一个。它们不是嵌套的。将线程视为正在执行"并排"更准确。

    启动第二个帖子的方式和位置并不重要。它只是一个线程,就像你的第一个线程一样,所以当你想从其中一个(非UI)线程中更新UI时,你在两种情况下都做同样的事情:安排你的UI更新代码在UI线程上,通过Dispatcher.InvokeDispatcher.InvokeAsync方法在WPF中完成。

    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 实例的位置和时间,但它并不确定&#34;其中&#34; A 。 (无论如何,课程都没有真正的位置。)所以说#34; AB&#34;之内是错误的。 (类型A通过B的方法引用a是指在执行<期间创建的对象实例< / em> B的实例方法,但它仍完全独立于B。)


更新:关于您在线程中了解如何使myTextBlock知道的问题,有两个解决方案:

  1. doSomthing个方法移动到MainWindow类中(并赋予它们唯一的名称)。

  2. myTextBlock传递给您的Thread1Thread2个对象:

    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); // <--
            …
        }
    }