0

I have a WinForms app with the following (skeleton) code:

namespace MyTrayApp
{
    public class SysTrayApp : Form
    {
        [STAThread]
        public static void Main()
        {
            try
            {
                SysTrayApp app = new SysTrayApp();
                Application.Run();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private NotifyIcon _trayIcon;
        private ContextMenu _trayMenu;

        private BackgroundWorker _bw = new BackgroundWorker();

        public SysTrayApp()
        {
            _trayMenu = new ContextMenu();
            _trayMenu.MenuItems.Add("Exit", OnExit);

            _trayIcon = new NotifyIcon();
            _trayIcon.Icon = new Icon(SystemIcons.Asterisk, 40, 40);

            _trayIcon.ContextMenu = _trayMenu;
            _trayIcon.Visible = true;

            _bw.WorkerReportsProgress = false;
            _bw.WorkerSupportsCancellation = true;
            _bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            _bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            _bw.RunWorkerAsync();
        }

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
        // do stuff
        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
            return;
            }
            Thread.Sleep(TimeSpan.FromMinutes(5)); // wait 5 minutes...
            _bw.RunWorkerAsync(); // then run again
        }
    }
}

The problem is that I can only right-click to open the ContextMenu when the app starts up. It seems that once the BackgroundWorker starts sleeping, it somehow blocks the ContextMenu. Thoughts?

kevlar1818
  • 3,055
  • 6
  • 29
  • 43

1 Answers1

3

Thread.Sleep is executed on the gui(main) thread (http://msdn.microsoft.com/en-us/library/ms171728.aspx) due to the way you've cread the BGW You should use a Timer instead Thread.Sleep 5 minutes.

Timer Class: http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx

Peter Ritchie
  • 35,463
  • 9
  • 80
  • 98
Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57
  • 2
    Doesn't this look like a question back? – King King Aug 13 '13 at 19:21
  • I could write the first parts as comment, the second as answer, i did combine it. – Jeroen van Langen Aug 13 '13 at 19:23
  • Convince me that the `Sleep` is executed on the GUI thread and you've got yourself at the least an upvote. – kevlar1818 Aug 13 '13 at 19:23
  • Just execute this: Debug.WriteLine(Thread.CurrentThread.ManagedThreadId); on the Constructor and the bw_RunWorkerCompleted. If the Id's are the same, then it's the same thread. – Jeroen van Langen Aug 13 '13 at 19:24
  • @KingKing that was when his answer was just "Isn't the Thread.Sleep executed on the gui(main)thread? You should use a Timer instead", which I'm pretty sure SO doesn't think is a good enough answer. Adding a link to the Timer class is *getting* there... – kevlar1818 Aug 13 '13 at 19:29
  • 1
    Ultimately, I think my problem is best solved by having a `Timer` trigger my `BackgroundWorker`'s `DoWork`, which is not described in this answer. – kevlar1818 Aug 13 '13 at 19:31
  • 3
    More specifically `RunWorkerCompleted` executes on the same thread that created the` BackgroundWorker` object (see reference in answer). – Peter Ritchie Aug 13 '13 at 19:35
  • as a side fyi [ProgressChanged](http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.progresschanged.aspx) has the same behavior. – Scott Chamberlain Aug 13 '13 at 19:42