WPF中的Dispatcher to Thread关系

我不完全清楚应用程序中有多少Dispatchers以及它们如何与Threads相关或引用。

据我了解,WPF应用程序有2个线程(一个用于输入,另一个用于UI)和1个调度程序(与UI-Thread相关联)。 如果我创建另一个线程 – 让我们称之为“工作线程” – 当我在工作线程上调用Dispatcher.CurrentDispatcher时,我会得到哪个调度程序怎么办?

另一种情况:假设一个带有2个线程的控制台应用程序 – 主线程和输入线程。 在主线程上,我首先创建输入线程,然后我调用Application.Run()

 Thread thread = new Thread(new ThreadStart(UserInputThreadFunction)); thread.Start(); Application.Run(); 

会有一个调度员,对吗? 在输入线程上,Dispatcher.CurrentDispatcher是否返回主线程的调度程序? 或者将实例获取到主线程调度程序的正确方法是什么?

可能是WPF应用程序中有多个调度程序吗? 有什么情况,创建另一个调度员是有意义的吗?

WPF应用程序有2个线程(一个用于输入,另一个用于UI)

这种说法并不完全正确。 WPF应用程序只有一个UI线程,可以处理所有UI交互和用户输入。 还有一个“隐藏”的线程负责渲染,但通常开发人员不处理它。

Dispatcher / Thread关系是一对一的,即一个Dispatcher始终与一个线程相关,可用于将执行分派给该线程。 Dispatcher.CurrentDispatcher返回当前线程的调度程序,也就是说,当您在工作线程上调用Dispatcher.CurrentDispatcher时,您将获得该工作线程的调度程序。

根据需要创建调度程序,这意味着如果您访问Dispatcher.CurrentDispatcher并且没有与当前线程关联的调度程序,则将创建一个调度程序。

话虽这么说,应用程序中的调度程序数总是小于或等于应用程序中的线程数。

默认情况下,WPF应用程序只有一个Dispatcher。 调度程序是唯一允许您与UI元素交互的线程。 它抽象了您的实现,因此您只需要担心在UI线程(即Dispatcher)上。

如果您尝试直接与可视化交互(例如,使用txtBkx.Text = "new"在文本框中设置文本),则从工作线程开始,您将不得不切换到UI线程:

 Application.Current.Dispatcher.Invoke( () => { txtBkx.Text = "new"; }); 

或者,您可以使用SynchronizationContext.Current (在UI线程上)并使用它来从不同的线程在UI线程上执行委托。 您应该注意,可能并不总是设置Dispatcher.CurrentDispatcher

现在,您可以在同一个应用程序中创建不同的WPF窗口,并为每个窗口配备一个单独的调度程序:

 Thread thread = new Thread(() => { Window1 w = new Window1(); w.Show(); w.Closed += (sender2, e2) => w.Dispatcher.InvokeShutdown(); System.Windows.Threading.Dispatcher.Run(); }); thread.SetApartmentState(ApartmentState.STA); thread.Start(); 

作为旁注,请记住在MVVM中,您可以从非UI线程更新模型并从非UI线程引发属性更改事件,因为WPF将为您封送PropertyChanged事件。 提升CollectionChanged必须在UI线程上。

调度程序始终与线程关联,并且线程最多只能有一个同时运行的调度程序。 线程不需要有调度程序。

默认情况下,只有一个Dispatcher – 用于UI。 有时候让其他调度员有意义,有时却没有。 调度线程需要在Dispatcher.Run()方法中阻塞,以便处理对调度程序的调用。 诸如控制台输入线程之类的线程将无法处理调用。