c# - 从后台线程和线程内的线程更新 UI

标签 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 类中,我想更新 MainWindow 中的 TextBlock >。

我看过以下解决方案,但没有发现这个问题涵盖了这种情况,而且我是初学者,发现它很难理解。

我可以使用上述问题中针对 Thread1 提供的解决方案,但是如何从 Thread2 更新 UI。
我使用的是.NET框架4.5。
最好的做法是什么。

最佳答案

…thread within a thread…

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

  • 线程不会在彼此“内部”执行。它们不是嵌套的。将线程视为“并行”执行更为准确。

    如何以及在何处启动第二个线程并不重要。它只是一个线程,就像您的第一个线程一样,因此当您想要从其中一个(非 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 委托(delegate)表示),这是其执行开始的地方,并且当线程到达该线程末尾时终止。

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

关于c# - 从后台线程和线程内的线程更新 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26293506/

相关文章:

c# - 如何使用矩阵旋转矩形并获得修改后的矩形?

c# - 如何在 T 为 double 或 Int 时在通用方法中使用 <T>.TryParse

c# - 在解决方案之间共享项目时的 NuGet

c# - RelayCommand不刷新执行/无法执行更改

c++ - 设计 C++ 休息客户端

python - 在守护进程中运行线程+队列

ruby - 如何检查文件是否仍被当前线程锁定?

c# - 为 csproj 禁用发布配置

c# - 有没有办法在 C# 4.5 中存储临时列表值?

c# - 枚举尚未开始或已经完成