【问题标题】:Dispatcher.Invoke is sometimes not calledDispatcher.Invoke 有时不会被调用
【发布时间】:2016-08-10 11:29:25
【问题描述】:

我的应用需要不时显示气球通知。我通过Dispatcher.Invoke() 执行此操作,该Action 创建NotifyIcon,显示气球通知,然后释放系统托盘图标。

public abstract class Foo {
    void Bar() {
        MainWindow.ShowTrayNotification(ToolTipIcon.Info, "Hello There!", "Balloon text here.");
    }
}

public partial class MainWindow : Window {

    static Dispatcher dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;

    public static void ShowTrayNotification(ToolTipIcon icon, string title, string text) {
        dispatcher.Invoke(new Action(() => {
            //anything here is not run
            UIHelper.ShowTrayNotification(icon, title, text); //static method
        }));
        //anything here is also not called if dispatcher.Invoke() is not run
    }
}

但是,有时Dispatcher.Invoke 不会运行。日志记录在它之前停止,并且在InvokeAction 内不会发生任何日志记录。

奇怪的是,当我触发 PC 关机时,突然Invoke 被触发(显示通知)并正常进行(执行我的关机前回调)。

我尝试做 Debug > Windows > Threads,但在 Debug 模式下问题不会发生,所以我找不到导致 UI 线程阻塞的原因。

这是什么原因造成的,我该如何解决?

更新

我尝试了以下方法,但它们不起作用:

  • 我把它改成了BeginInvoke

  • 我添加了DispatcherPriority.Send

更新 2

public class UIHelper
{
    public static void ShowTrayNotification(ToolTipIcon icon, string title, string text) {
        NotifyIcon trayIcon = new NotifyIcon();
        trayIcon.Icon = MyApp.Properties.Resources.myIcon;
        trayIcon.Text = "MyApp";
        trayIcon.BalloonTipClosed += TrayNotificationClosed;
        trayIcon.Visible = true;
        trayIcon.ShowBalloonTip(5000, title, text, icon);
    }

    static void TrayNotificationClosed(object sender, EventArgs e) {
        ((NotifyIcon)sender).Visible = false;
        ((NotifyIcon)sender).Icon = null;
        ((NotifyIcon)sender).Dispose();
        sender = null;
    }
}

【问题讨论】:

  • 如何调用对象本身的调度程序?像UIHelper.Dispatcher.Invoke... 或者你可以尝试在调度程序之前放置一个MessageBox。Invoke 以查看该方法是否运行。这只是一个建议。
  • Dispatcher.Invoke() 当你的应用程序的 UI 线程被其他东西占用时会死锁。使用 Debug > WIndows > Threads 调试器窗口进行诊断。
  • @JakubLokša dispatcher.Invoke 永远不会运行。我使用MainWindow 中的调度程序确保UIHelper 中的NotifyIcon 在主UI 线程中创建,否则它不会显示。
  • @HansPassant 使用BeginInvoke 会有什么不同吗?我可以尝试一下,但问题非常间歇性。
  • UIHelper.ShowTrayNotification会不会锁定UI线程?

标签: c# multithreading visual-studio-2013 static-methods notifyicon


【解决方案1】:

试试这样:

public partial class MainWindow : Window
    {

        static Dispatcher dispatcher = System.Windows.Application.Current.Dispatcher;

        public static void ShowTrayNotification(ToolTipIcon icon, string title, string text)
        {
            if (dispatcher != null && !dispatcher.CheckAccess())
            {
                dispatcher.Invoke(() => ShowTrayNotification(icon, title, text));
                return;
            }
            UIHelper.ShowTrayNotification(icon, title, text);

        }
    }

另见Dispatcher.CurrentDispatcher vs. Application.Current.Dispatcher

【讨论】:

  • 看起来很有希望,我第一次听说CheckAccess。为什么需要它?文档说determines whether the calling thread is the thread associated with this Dispatcher.。为什么我们不希望调用线程成为与System.Windows.Application.Current.Dispatcher 关联的线程?在这种情况下,为什么ShowTrayNotification 会调用自己?
  • 该方法检查呼叫是否已经来自指定的调度程序。如果调度程序尚未在 UI 线程上执行,您只想调用调度程序上的方法
  • 但是我不需要在UI线程上执行吗?我之前试过不使用Dispatcher.Invoke,它不会显示我的通知。
  • 自我调用只是为了确保 UI 线程上始终运行相同的方法,并且您不必为它实现 2 种不同的方法
  • UI 操作需要在 UI 线程上运行。控件始终有自己的 Dispatcher,但您的 Helper 类不是 Control,因此您必须确保调用在 UI 线程上运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多