问题
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.
来源:https://stackoverflow.com/questions/15041241/wait-for-process-to-end-async-and-then-call-a-function-within-the-main-form