WPF中的Dispatcher to Thread关系

j00*_*0hi 24 .net c# wpf dispatcher

我不完全清楚应用程序中有多少Dispatchers以及它们与Threads相关或引用的方式.

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

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

Thread thread = new Thread(new ThreadStart(UserInputThreadFunction));
thread.Start();
Application.Run();
Run Code Online (Sandbox Code Playgroud)

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

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

Pav*_*kov 28

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

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

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

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

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


小智 12

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

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

Application.Current.Dispatcher.Invoke(
    () => { txtBkx.Text = "new"; });
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用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();  
Run Code Online (Sandbox Code Playgroud)

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