MrBeatnik
MrBeatnik

Reputation: 97

Windows Form run external process without blocking UI

I want to:

  1. Show a form with a textbox.
  2. Run an external program (notepad.exe for ease of example).
  3. Continue to allow the user to enter data into the form textbox whilst notepad is running.
  4. Run some more (continue) native form code when notepad closes. This will update the form, amongst other things.

I'm having problems making this happen. I'm aware of a multitude of posts about this similar issue, but haven't found a solution that works for me.

I have tried:

What would be the neatest, and simplest solution for a simple Windows Form program? There are no extra classes used, and all code is in the Form1 class.

Upvotes: 2

Views: 5982

Answers (4)

Servy
Servy

Reputation: 203847

The Process class fires an Exited event when the process exits. You can add a handler to that event to execute code when the process exits without blocking the UI thread:

process.EnableRaisingEvents = true;
process.Exited += (s, args) => DoStuff();

Alternatively you could create a Task that represents the completion of the process to leverage the TPL for asynchrony:

public static Task WhenExited(this Process process)
{
    var tcs = new TaskCompletionSource<bool>();
    process.EnableRaisingEvents = true;
    process.Exited += (s, args) => tcs.TrySetResult(true);
    return tcs.Task;
}

This would allow you to write:

await process.WhenExited();
UpdateUI();

Upvotes: 5

Tugay Karacay
Tugay Karacay

Reputation: 46

You should start process in BackgroundWorker so you can catch complete event on same thread.

        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += delegate {
            Process proc = Process.Start("YOUR-PROCESS-PATH");
            proc.Start();
            proc.WaitForExit();
        }
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.RunWorkerAsync();

then catch the worker ended event on called thread;

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        //Do your thing o UI thread
    }

Upvotes: 1

lordjeb
lordjeb

Reputation: 1306

Here is my favorite way to do something like this with a BackgroundWorker. This has the advantage of the RunWorkerCompleted callback being on the main thread, so it can interact with the UI.

public partial class Form1 : Form
{
    ...
    private BackgroundWorker wrk;
    private void button1_Click(object sender, EventArgs e)
    {
        wrk = new BackgroundWorker();
        wrk.DoWork += (s, ea) => { /*Create your process and wait here*/ };
        wrk.RunWorkerCompleted += (s, ea) => { textBox1.Text = "Finished"; };
        wrk.RunWorkerAsync();
    }
}

Upvotes: 2

Darek
Darek

Reputation: 4797

Here you go:

    void Form1_Load(object sender, EventArgs e)
    {
        Task.Factory.StartNew(() =>
        {
            var p = Process.Start("notepad.exe");
            p.WaitForExit();
        }).ContinueWith(antecedant => { MessageBox.Show("Notepad closed"); });
    }

Upvotes: 2

Related Questions