我有一个 FileSystemWatcher,它对 Changed 事件使用react。
我想打开文件,阅读其内容,在文本框中显示它,并隐藏 1 秒后创建的弹出窗口。代码几乎可以工作,但在隐藏弹出窗口时出现问题。
下面是一段代码:
txtLog.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate() {
this.txtLog.Text = dataToDisplay;
extendedNotifyIcon_OnShowWindow();
Thread threadToClosePopup = new Thread(new ThreadStart((Action)delegate() {
Thread.Sleep(1000);
extendedNotifyIcon_OnHideWindow();
}));
threadToClosePopup.Start();
});
如您所见,我使用 Invoke 来设置文本,因为事件在不同的线程 (FileSystemWatcher) 中。但是为了隐藏窗口,extendedNotifyIcon_OnHideWindow() 不会在 GUI 的线程中执行。如何在 GUI 线程中执行它?
最佳答案
这适用于带有 MVVM
的 WPF
。
Application.Current.Dispatcher.Invoke(
() =>
{
// Code to run on the GUI thread.
});
这将不会始终如一地工作(如果我们在响应式扩展的处理程序中,它将失败):
Dispatcher.CurrentDispatcher.Invoke(
() =>
{
// Fails if we are inside a handler for Reactive Extensions!
});
专家额外:原因?
根据设计,任何线程都可以有一个与之配对的调度程序线程,请参阅 MSDN: Dispatcher Class .
如果我们从任何线程引用 Dispatcher.CurrentDispatcher
,它实际上会创建一个新的调度程序线程,它独立于官方 WPF UI 调度程序线程。当我们尝试在这个新创建的调度程序线程上执行代码时,WPF 将抛出异常,因为它不是官方的 UI 调度程序线程。
解决方案是始终使用 Application.Current.Dispatcher.Invoke()
或 Application.Current.Dispatcher.BeginInvoke()
。参见 What's the difference between Invoke() and BeginInvoke() .
更新 2020-05-02:可以使用多个 WPF UI 调度程序线程运行 WPF 应用程序。我使用一个正在执行此操作的大型 WPF 应用程序。让它工作是很棘手的,但一旦它工作了 - 它是惊人的,并且整个应用程序的运行速度提高了一个数量级,因为有多个 UI 调度程序线程。很高兴回答这方面的问题。
测试于:
WPF
.NET 4.5
.NET 4.6
.NET 4.61
关于c# - 如何在 GUI 线程中执行代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3718590/