c# - 如何在 GUI 线程中执行代码?

标签 c# wpf multithreading c#-4.0

我有一个 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 线程中执行它?

最佳答案

这适用于带有 MVVMWPF

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/

相关文章:

c - Linux中进程和线程的区别

c++ - Map 与 Unordered_map——多线程

C# XML 序列化 - 削弱封装?

C#:HttpClient,服务器违反了协议(protocol)。部分=响应状态行

wpf - 使用 XAML 在圆心绘制 "x"的问题

c# - 什么是白标 dll 的好方法

c# - 特殊日期时间格式为字符串,看起来像 double

c# - Flickr API key 存储

c# - C#中如何使用文件流复制文件

c++ - 互斥体的存在是否有助于摆脱 volatile 关键字?