Wait for process to end async and then call a func

2019-03-05 03:09发布

问题:

I'm coding an editor for a game with C#. My programm openes as .txt File by starting a notepad.exe process. If that process exits, I want to call a function within the main form (to update the textbox). Here's what I'm doing so far:

 void OpenTextEditor(TreeNode node) 
    {
        Process editor = new Process();
        editor.StartInfo.WorkingDirectory = "%WINDIR%";
        editor.StartInfo.FileName = "notepad.exe";
        var txtfilelocation = GetRealPathByNode(node);
        var txtfile = File.ReadAllText(txtfilelocation,Encoding.Default);
        txtfile = txtfile.Replace("\n", "\r\n");
        File.WriteAllText(txtfilelocation,txtfile,Encoding.Default);
        editor.StartInfo.Arguments = txtfilelocation;
        editor.EnableRaisingEvents = true;
        editor.Exited += delegate {
            NotePadHasEnded(node);
        };
        editor.Start(); //starten  
    }

    public Delegate NotePadHasEnded(TreeNode node)
    {
        var txtfilelocation = GetRealPathByNode(node);
        var newfileloc = txtfilelocation;
        var newfile = File.ReadAllText(newfileloc, Encoding.Default);
        newfile = newfile.Replace("\r\n", "\n");
        File.WriteAllText(txtfilelocation, newfile, Encoding.Default);

        if (treeView1.SelectedNode == node) DisplayText(node);

        return null;
    }

The GetRealPathByNode() function returns a string of the full path of the File which the TreeView node points at. DisplayText() reads the text from the file the node points at and displays that in a richtextbox.

Upon executing, my main form is still usable as I wanted it, but when the process is terminated (notepad closed), it throws an error stating that the function NotePadHasEnded has no access to the treeView1 object because it is being executed in another process.

How can I create a process that calls a function in my main form when it is being exited, asynchronously? I know that it works when I use the WaitForExit() function, but then my Form freezes and waits until notepad closes. I want the user to be able to open up other txt files with the editor and when one editor is being closed that the richtextbox text ist being updated in my GUI.

/Edit/ Now Solved. Thanks to Woodman's answer, I replaced

            editor.Exited += delegate {
            NotePadHasEnded(node);
            };

with

  editor.Exited += delegate
        {
            this.Invoke((MethodInvoker)delegate()
            {
                NotePadHasEnded(node);
            });
        };

回答1:

You should use Dispatcher.Invoke or Dispatcher.BeginInvoke inside NotePadHasEnded() method to switch to UI thread as you only allowed to access UI objects from UI thread.

Check this post for further details.



回答2:

Google for SynchronizationContext. The error occures because you UI thread is not syncronized with the second thread that runs then the editor was closed. I found a few examples that describe how to implement the syncronization: It's All About the SynchronizationContext and ExecutionContext vs SynchronizationContext. Hope this helps you ;-)



回答3:

The Exited event occurs in another thead, and you can only access UI controls in their own thread (which is called UI thread). Since you are using Windows Forms, you should use the Control.Invoke method:

editor.Exited += delegate
{
    node.TreeView.Invoke(new Action<TreeNode>(NotePadHasEnded), node);
};

Also change the return type of the NotePadHasEnded to void.

node.TreeView is used to access the Invoke method. You can use any UI control. If the code resides in a form, you can use this instead.