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

Pat*_*ins 6 c# wpf multithreading c#-4.0

我有一个FileSystemWatcher,可以对Changed事件做出反应.

我想打开文件,阅读其内容,将其显示在文本框中,并隐藏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();
        });
Run Code Online (Sandbox Code Playgroud)

如您所见,我使用Invoke来设置文本,因为事件位于不同的线程(FileSystemWatcher)中.但是为了隐藏窗口,extendedNotifyIcon_OnHideWindow()不会在GUI的线程中执行.如何在GUI线程中执行它?

Con*_*ngo 21

这非常适用于WPF有MVVM.

Application.Current.Dispatcher.Invoke(
    () =>
    {
         // Code to run on the GUI thread.
    });
Run Code Online (Sandbox Code Playgroud)

这将无法一致地工作(如果我们在Reactive Extensions的处理程序中,它将失败):

Dispatcher.CurrentDispatcher.Invoke(
    () =>
    {
         // Fails if we are inside a handler for Reactive Extensions!
    });
Run Code Online (Sandbox Code Playgroud)

专家额外:原因?

根据设计,任何线程都可以有一个与之配对的调度程序线程,请参阅MSDN:Dispatcher Class.

如果我们Dispatcher.CurrentDispatcher从任何线程引用,它实际上将创建一个新的调度程序线程,该线程与官方WPF UI调度程序线程分开.当我们尝试在这个新创建的调度程序线程上执行代码时,WPF将抛出,因为它不是官方的UI调度程序线程.

解决方案是始终使用Application.Current.Dispatcher.Invoke(),或Application.Current.Dispatcher.BeginInvoke().请参阅Invoke()和BeginInvoke()之间的区别.


测试:

  • WPF
  • .NET 4.5
  • .NET 4.6
  • .NET 4.61


Jar*_*Par 10

要extendedNotifyIcon_OnHideWindow在GUI线程上执行该方法,请使用Dispatcher您执行的操作来显示它.

Thread threadToClosePopup = new Thread(new ThreadStart((Action)delegate() { 
  Thread.Sleep(1000); 
  txtLog.Dispatcher.Invoke(
    DispatcherPriority.Normal,
    (Action)() => extendedNotifyIcon_OnHideWindow());
}));
Run Code Online (Sandbox Code Playgroud)