在我的控制台应用程序中,我一直在尝试启动 STA 线程并显示WPF
窗口。我已经成功地展示了窗口,但是使用Dispatcher
的库遇到了问题(准确地说是System.Reactive.Windows.Threading
(。我已经使用此文档中的代码解决了我的问题 - 我缺少的是System.Windows.Threading.Dispatcher.Run()
在适当的时候打电话给。
但是在仔细阅读本文(和其他文章(并检查Dispatcher's
API 后,我仍然不知道:如何判断WPF Dispatcher
已正确初始化并正在运行?对于需要Dispatcher
的库来说,如果他们可以检查的话,这将是非常有用的。
--编辑--
杜尼奥@Peter言论后扩展我的问题
有了 C# 控制台应用程序,我想创建一个 WPF 窗口,我将在其中观察调度程序上的一些数据。完整代码在这里
所以我有我的程序,其中主类看起来像这样:
static void Main(string[] args)
{
var observable = Observable
.Interval(TimeSpan.FromMilliseconds(500))
.TakeWhile(counter => counter < 10);
var thread = new Thread(() =>
{
new TestWindow(observable);
Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
Console.ReadKey();
}
我在这里创建了一个带有 Interval 运算符的可观察量,它每 500 毫秒滴答一次,并将其传递给我在单独的线程上运行的 TestWindow(下面的代码(。在 10 次刻度后,我结束了可观察的序列。
TestWindow
类:
public class TestWindow : Window
{
public TestWindow(IObservable<long> observable)
{
var isDispatcherInitialized = false;
Dispatcher.Invoke(() => isDispatcherInitialized = true, DispatcherPriority.ApplicationIdle);
if (!isDispatcherInitialized)
throw new ApplicationException("Dispatcher not initialized");
observable
.ObserveOnDispatcher()
.Window(TimeSpan.FromMilliseconds(600))
.Subscribe(_ => Console.WriteLine($"OnNext, observed on dispatcher with Window operator"));
}
}
在测试窗口中,我在调度程序(ObserveOnDispatcher()
(上观察我的可观察量,并且我使用窗口运算符。
该代码的问题(在.NET Framework和.NET Core 3.0预览版上测试(:
- 如果我在启动 STA 线程时不调用
Dispatcher.Run();
,则我调用Dispatcher.Invoke()
的验证将通过,但ObserveOnDispatcher()
将无法正常工作 - 订阅永远不会停止,并且消息:"OnNext,使用 Window 运算符在调度程序上观察到"将永远存在。
这就是为什么我想知道我是否可以检测到调度程序的状态。
如果您详细说明此声明,将会很有帮助:
对于需要
Dispatcher
的库来说,如果他们可以检查的话,这将是非常有用的。
也就是说,为什么它会有用?
首先,如果您使用的是第三方库(例如您提到的 .NET 的反应式扩展 (Rx(,您如何知道如何检查调度程序状态对该库的帮助?
另一方面,什么场景不适合你?由于缺乏要解决的具体问题,您的问题相当开放。目前尚不清楚哪种类型的答案可以真正解决您的问题。
也就是说,我想到了两件事:
- 如果您想知道是否已为给定线程创建了调度程序,则应调用
System.Windows.Threading.Dispatcher.FromThread(System.Threading.Thread.CurrentThread);
如果尚未为该线程创建调度程序,这将返回null
,如果已创建调度程序,则返回对调度程序的引用。 - 如果你想知道调度程序已经完成初始化并准备好调度东西,在我看来,最简单的办法就是要求它调度一些东西,当它这样做时,它就准备好了。使用一个调用方法(
BeginInvoke()
、Invoke()
或InvokeAsync()
(的重载来获取DispatcherPriority
值,你可以得到关于初始化级别发生的细粒度信息。例如,如果您传递DispatcherPriority.Normal
或DispatcherPriority.Send
,则在调用委托时,您将知道调度程序正在运行。但是,如果您传递DispatcherPriority.ApplicationIdle
或DispatcherPriority.SystemIdle
,您将知道调度程序不仅正在运行,而且还清除了要调度的初始事件的积压工作,并且应用程序正在等待用户输入。