我有以下应用程序结构:
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
// ------------------------------
}
}
从这两个线程 Thread1
和 Thread2
类中,我想更新 MainWindow
中的 TextBlock
>。
我看过以下解决方案,但没有发现这个问题涵盖了这种情况,而且我是初学者,发现它很难理解。
- How to update UI from another thread running in another class
- How to update the GUI from another thread in C#?
- Update UI from background Thread
我可以使用上述问题中针对 Thread1
提供的解决方案,但是如何从 Thread2
更新 UI。
我使用的是.NET框架4.5。
最好的做法是什么。
最佳答案
…thread within a thread…
看来您对线程是什么有一些误解。让我们看看这些:
线程不会在彼此“内部”执行。它们不是嵌套的。将线程视为“并行”执行更为准确。
如何以及在何处启动第二个线程并不重要。它只是一个线程,就像您的第一个线程一样,因此当您想要从其中一个(非 UI)线程中更新 UI 时,您在这两种情况下都会执行完全相同的操作:在 UI 线程上安排 UI 更新代码,这是在 WPF 中通过
Dispatcher.Invoke
或Dispatcher.InvokeAsync
方法完成的。myTextBlock.Dispatcher.Invoke(() => { … /* update myTextBlock here */ }); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // this will be scheduled on the correct (UI) thread
线程与
Thread1
和Thread2
对象不同。将线程视为代表代码的执行路径;或者如果您愿意的话,可以单独执行的方法。线程有一个入口点(一个方法,由 ThreadStart 委托(delegate)表示),这是其执行开始的地方,并且当线程到达该线程末尾时终止。class Thread1 { … void doSomthing() { … Thread2 thread2 = new Thread2(); new Thread(new ThreadStart(thread2.doSomthing)).Start(); } }
即使您将类命名为
Thread1
和Thread2
,但这并不会使它们成为线程。它们是常规的 .NET 类,恰好包含用作线程入口点的方法。线程仅由 Thread 类表示(请注意,您的类不会也不可能从 Thread 继承)。再说一次,你在哪里.Start()
它们发生并不重要;它们彼此独立。当你遇到这样的事情时:
class A { … } class B { void Foo() { var a = new A(); … }
B
仅参与A
实例的创建时间和地点,但它并不决定“在何处”A
是。 (无论如何,类实际上没有位置。)因此说“A
在B
内”是错误的。 (A
类型由B
的方法引用,a
引用一个对象实例,该实例得到在B
的实例方法执行期间创建,但它仍然完全独立于B
。)
更新:关于下面添加的关于如何让您的线程知道 myTextBlock
的问题,有两种解决方案:
将两个
doSomthing
方法移至MainWindow
类中(并为它们指定唯一的名称)。将
myTextBlock
传递给您的Thread1
和Thread2
对象: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/