0

Мое приложение должно время от времени показывать уведомления о воздушном шаре. Я делаю это через Dispatcher.Invoke(), который выполняет Action, который создает NotifyIcon, отображает уведомление о шаре, а затем отображает значок в системном трее.Dispatcher.Invoke иногда не называется

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.

Что странно в том, что когда я запускаю остановку ПК, внезапно запускается Invoke (уведомление отображается) и работает нормально (мои обратные вызовы перед выключения выполняются).

Я попытался выполнить Debug> Windows> Threads, но проблема не возникает в режиме отладки, поэтому я не могу найти то, что вызывает блокировку потока пользовательского интерфейса.

Что вызывает это и как я могу его исправить?

UPDATE

Я попытался следующие, и они не работали:

  • Я изменил его BeginInvoke.

  • Я добавил DispatcherPriority.Send.

UPDATE 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; 
    } 
} 
+1

Как о вызове диспетчера на сам объект? например, 'UIHelper.Dispatcher.Invoke ...' Или вы можете попробовать поставить «MessageBox» перед диспетчером. Попробуйте проверить, работает ли даже этот метод. Это всего лишь предложение. –

+0

Dispatcher.Invoke() будет тупиком, когда поток пользовательского интерфейса вашего приложения занят чем-то другим. Используйте окно Debug> WIndows> Threads debugger для диагностики. –

+0

@ JakubLokša 'dispatcher.Invoke' никогда не запускается. Я использую диспетчера в 'MainWindow', чтобы убедиться, что' NotifyIcon' в 'UIHelper' создан в основном потоке пользовательского интерфейса, иначе он не отображается. – Obay

ответ

0

Попробуйте так:

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 Также см

+0

Выглядит многообещающе, впервые услышал о 'CheckAccess'. Зачем это нужно?Документы говорят, что «определяет, является ли вызывающий поток потоком, связанным с этим Диспетчером». Почему мы не хотим, чтобы вызывающий поток был потоком, связанным с 'System.Windows.Application.Current.Dispatcher'? И почему «ShowTrayNotification» вызывает себя в этом случае? – Obay

+0

Метод проверяет, идет ли звонок уже от указанного Диспетчера. Вы просто хотите вызвать метод в диспетчере, если он еще не выполняется в потоке пользовательского интерфейса – KroaX

+0

Но разве мне не нужно выполнять в потоке пользовательского интерфейса? Я пробовал НЕ использовать 'Dispatcher.Invoke' раньше, и он не отобразил мое уведомление. – Obay