我不完全清楚应用程序中有多少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应用程序中有多个调度程序吗?是否有任何情况,创建另一个调度员是否有意义?
答案 0 :(得分:27)
WPF应用程序有2个线程(一个 用于输入,另一个用于UI)
这句话并不完全正确。 WPF应用程序只有一个UI线程来处理所有UI交互和用户输入。还有一个“隐藏”的线程负责渲染,但通常开发人员不处理它。
Dispatcher / Thread关系是一对一的,即一个Dispatcher始终与一个线程相关联,并且可用于将执行分派给该线程。 Dispatcher.CurrentDispatcher
返回当前线程的调度程序,也就是说,当您在工作线程上调用Dispatcher.CurrentDispatcher
时,您将获得该工作线程的调度程序。
根据需要创建调度程序,这意味着如果您访问Dispatcher.CurrentDispatcher
并且没有与当前线程关联的调度程序,则会创建一个调度程序。
话虽这么说,应用程序中的调度程序数总是小于或等于应用程序中的线程数。
答案 1 :(得分:10)
默认情况下,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线程上。
答案 2 :(得分:3)
dispatcher始终与线程相关联,并且线程最多可以同时运行一个调度程序。线程不需要有调度程序。
默认情况下,只有一个Dispatcher - 用于UI。有时候让其他调度员有意义,有时却没有。调度线程需要在Dispatcher.Run()
方法中阻塞,以便处理对调度程序的调用。诸如控制台输入线程之类的线程将无法处理调用。