views:

164

answers:

4

I'm having trouble getting my GUI to appear and not freeze while running (and waiting for) an outside process. In this case, drivers.exe is a very simply program where the user simply clicks "OK". So whenever I click OK, it exits. I am trying to simply make my status strip count numbers up (really fast) as drivers.exe is executing. But in practice, my GUI never appears at all until drivers.exe exits.

private void run_drivers()
        {
            Console.WriteLine("Start Driver");
            int driver_timeout_in_minutes = 20;
            System.Diagnostics.Process driverproc = System.Diagnostics.Process.Start(Application.StartupPath + "\\" + "drivers.exe");
            driverproc.WaitForExit(driver_timeout_in_minutes * 1000 * 60);   //uses milliseconds, we must convert
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ThreadStart worker = new ThreadStart(run_drivers);
            Console.WriteLine("Main - Creating worker thread");
            toolStripStatusLabel1.Text = "hi";
            Thread t = new Thread(worker);
            t.IsBackground = true;
            t.Start();
            Console.WriteLine("Main - Have requested the start of worker thread");

            int i = 0;
            while (t.IsAlive)
            {
                i++;
                toolStripStatusLabel1.Text = i.ToString();
            }
            Console.WriteLine("Dead");
        }
+2  A: 

You should look into a BackgroundWorker, as it does all the threading work for you

phsr
Could you please show me how? I did give it a shot, and it really didn't work at all. My form still wouldn't show...at all, in fact.
Adam
The problem is the "while(t.IsAlive)" loop. He needs to get that off the UI thread whether he uses BackgroundWorker or not.
Phil
+2  A: 

The reason that your form does not show until drivers.exe has run is because you are running drivers.exe from within Form.Load. Form.Load occurs before the form is shown. Try running drivers.exe in Form.Shown instead.

Also, while(t.IsAlive) will technically block your UI thread. If that is not what you want, it should be moved off the main thread. You will also probably want to call toolStripStatusLabel1.Refresh() to force the label to refresh after you set its text.

Zach Johnson
Whether the code's running in Form.Load or later, the UI thread will still not get time to paint the screen when executed as shown.
Michael Petrotta
A: 

don't put any loop on GUI thread. it will freeze your application. Loop has to be on background thread which should update toolStripStatusLabel1 through Invoke method.

see this example. untested. maybe it might even work just like this...

    private void run_drivers()
    {
        Console.WriteLine("Start Driver");
        int driver_timeout_in_minutes = 20;
        System.Diagnostics.Process driverproc = System.Diagnostics.Process.Start(Application.StartupPath + "\\" + "drivers.exe");
        int i = 0;
        var action = new Action<int>(x => {  toolStripStatusLabel1.Text = i.ToString(); })
        while (!driverproc.HasExited)
        {
            i++;
            toolStripStatusLabel1.Invoke(action);
        }

        Console.WriteLine("Dead");
        // start another thread here...
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        ThreadStart worker = new ThreadStart(run_drivers);
        Console.WriteLine("Main - Creating worker thread");
        toolStripStatusLabel1.Text = "hi";
        Thread t = new Thread(worker);
        t.IsBackground = true;
        t.Start();
        Console.WriteLine("Main - Have requested the start of worker thread");
    }
lubos hasko
Okay, that makes sense. But how then do I wait to execute one function until another one is finished?For example, say I want to execute func_2 only after func_2 is completed, both of which will take several minutes to complete.
Adam
start new thread on the last line of `run_drivers()` method. just stay away from loops on GUI thread.
lubos hasko
A: 

One solution you could use, while retaining your current code structure, is to update the UI periodically on a timer thread, stopping the timer when the thread completes. Doing this, you'll change from a loop to an event-driven design, and you'll give the UI thread time to paint your form.

// create a System.Windows.Forms.Timer through the designer or in code.
// give it a short interval if you want the counter to increment quickly.

int counter;

private void Form1_Load(object sender, EventArgs e)
{
    ...
    t.Start();
    counter = 0;
    timer.Start();
    ....
}

private void timer_Tick(object sender, EventArgs e)
{
   if (t.IsAlive)
   {
       counter++;
       toolStripStatusLabel1.Text = counter.ToString(); 
   }
   else
   {
      timer.Stop();
   }
}

(Untested)

Michael Petrotta