tags:

views:

615

answers:

4

Consider the following snippet:

if(form1.isLoggedIn) {             
        //Create a wait handle for the UI thread.
        //the "false" specifies that it is non-signalled
        //therefore a blocking on the waitone method.
        AutoResetEvent hold = new AutoResetEvent(false);

        filename = Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData), DateTime.Now.ToString("ddMMyyhhmm") + "-" + form1.username);       

        Flow palm = new Flow(new FlowArguments(form1.username, filename), hold);

        System.Windows.Forms.NotifyIcon notifyIcon = new System.Windows.Forms.NotifyIcon();
        System.Windows.Forms.ContextMenuStrip notificationIconContext = new System.Windows.Forms.ContextMenuStrip();
        //Create a context menu strip
        ToolStripMenuItem contextAbout = new ToolStripMenuItem("About");
        ToolStripMenuItem contextExit = new ToolStripMenuItem("Exit");

      //properties of notifyicon that SO dosnt care for including a event handler for the mouse click events.


        //wait for the background thread to finish.                
        hold.WaitOne(Timeout.Infinite);




        MessageBox.Show("Thankyou, exiting...");
        form1.Dispose();                
    }

As you see The FLOW class is pretty simple. It just has a Threading.Timer which is run. Therefore on the UI thread i have to call WaitHandle.WaitOne() method, because otherwise the UI thread finishes and therefore ending the application..

My goal: Since there's no GUI, i want to create a notify icon. It works and everything,except I can't click on it and its not responsive, this is because it is created on the UI thread. I can't put it in the flow class because the Flow class is also on the UI thread (the timer in the Flow class is in background thread).

So how can I keep my notifyicon responsive while running the timer in the Flow class? I thought waithandle was my solution but since its a blocking method it doesn't work.

Any other ideas/solutions?

edit: response to Rich's answer: The Flow class is on the background thread and everything runs the way it should. But if I don't add the waithandle in the UI thread, the main() finishes on the UI thread therefore terminating the whole program. (even though the timer is enabled on the background thread). Is there another solution to waithandle? because I have to leave it in for the Flow class to do its thing. If I take it out, the program ends, if I leave it in it blocks the UI thread therefore my notifyicon dosnt work.

A: 

I don't know what your Flow object is or what it does, but why can't it do it's work in another thread and not block the UI thread? I would think that the notify icon is a part of the UI and therefore required to be on the UI thread making it the wrong candidate for being run on another thread. In contrast, your Flow object seems to be executing the logic of your application which would make more sense to be spawned on another thread.

Rich
Hi, please read my edit.
masfenix
A: 

Alive threads not marked as background threads will prevent the program from exiting.

ermau
A: 

I'm reading between the lines a bit here, but I think Rich is right - you need to move the background processing off the UI thread:

  • Remove the form1.dispose call from the function above - I imagine that this is your only form, which is why once you dispose of it the application exits.
  • Call the flow class asynchronously - the simplest way to do this is to call ThreadPool.QueueUserWorkItem() on a delegate which calls the function (although you're not really supposed to use thread pool threads for long running operations, but I doubt it will hurt in this case)
  • Once the flow method is done, call back to the UI thread to let it know. You can do this by calling form1.Invoke with a suitable delegate
  • In the function which is then called (i.e. on the UI thread) close the form and exit your application

So the end result looks like 3 functions:

  • the function above, which starts the processing in the background and then returns without waiting
  • the background processing function, executed on a seperate thread
  • the function called on the UI thread when processing is complete, which closes the application
A: 

As ermau mentioned, foreground threads will prevent the process from terminating.

So one solution is to change your Flow class so that it uses foreground threads. Since Threading.Timer executes on a ThreadPool thread supplied by the system you will have to use something else.

If you don't want to modify your Flow class, another solution is to create a foreground thread (other than your UI thread) that will wait on the handle.

Thread t = new Thread((ThreadStart)delegate { hold.WaitOne(); });
t.Start();

This creates a thread that will block until your handle "hold" is signaled by your worker thread but won't block your UI thread.

dss539