使用Timer时未触发事件处理程序

时间:2016-07-26 11:05:30

标签: c# visual-studio-2013 timer notifyicon

我想在我需要显示气球提示时显示系统托盘图标,然后在气球提示关闭时隐藏图标。

但是,一旦显示图标,我就无法让它消失,因为事件处理程序没有被触发:

public partial class MainWindow : Window {

    public static NotifyIcon trayIcon = new NotifyIcon();

    public MainWindow() {
        InitializeTrayIcon();
    }

    void InitializeTrayIcon() {
        trayIcon.Text = "My App";
        trayIcon.Icon = MyApp.Properties.Resources.myIcon;
        trayIcon.Visible = false;

        //the following never gets fired:
        trayIcon.BalloonTipClosed += (sender, e) => {
            trayIcon.Visible = false; 
        };
      }

      public static void ShowTrayNotification(ToolTipIcon icon, string title, string text, int duration) {
          trayIcon.Visible = true;
          trayIcon.ShowBalloonTip(duration, title, text, icon);
      }
}

从计时器触发的方法调用ShowTrayNotification()

public abstract class Watcher {

    protected System.Timers.Timer myTimer = new System.Timers.Timer(1000);

    //the following is called in a subclass of Watcher, which is instantiated in MainWindow
    protected void SetupMyTimer() {
        myTimer.AutoReset = true;
        myTimer.Elapsed += myTimer_Elapsed;
        myTimer.Start();
    }

    protected virtual void myTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
        myTimer.Enabled = false;
        MyTimerElapsedCallback();
        myTimer.Enabled = true;
    }

    void MyTimerElapsedCallback() {
        MainWindow.ShowTrayNotification(ToolTipIcon.Info, "Hello There!", "Balloon text here.", 5000);
    }
}

所以显示了气球。但BalloonTipClosed中的MainWindow永远不会被解雇。

我试过了:

  • 将(1)创建NotifyIcon,(2)显示气球,以及(3)设置BalloonTipClosed全部放在MainWindow中,并且工作正常(即BalloonTipClosed被解雇)

  • 将(1),(2)和(3)放在SetupMyTimer()中,它也可以正常工作

  • 将(1),(2)和(3)放在MyTimerElapsedCallback()中,工作(即BalloonTipClosed未被解雇)

  • BalloonTipClosed更改为BalloonTipClicked也可以。

  • 使用非lambda BalloonTipClosed EventHandler,工作。

有了这个,我认为问题与Timer有关,但我不知道它如何影响事件处理程序,也不知道如何解决。

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

您的代码中存在线程错误,计时器的Elapsed事件是在线程池线程上引发的。当您执行此类操作时通常会收到InvalidOperationException,但NotifyIcon没有实现检查。

在错误的线程上显示它的副作用是在该坏线程上创建用于接收事件通知的其他隐藏窗口。它根本无法接收任何通知,线程池线程不会引发消息循环。糟糕的诊断,没有例外,没有好办法看出它为什么会出错。

您的ShowTrayNotification()方法必须使用表单的BeginInvoke()方法,以便代码在UI线程上运行。你这么做很难,因为这个方法是静态的,在绝对的捏合中你可以使用Application.OpenForms [0] .BeginInvoke()。但是让你的Watcher课程提出一个事件而不是直接调用表格的方法肯定会更好。或者考虑使用简单的Winforms'计时器,您在工具箱中找到的计时器。发布时,Watcher类没有明显的附加价值。