【问题标题】:Wait for process to end async and then call a function within the main form等待进程结束异步,然后在主窗体中调用函数
【发布时间】:2013-02-23 13:51:57
【问题描述】:

我正在用 C# 编写一个游戏的编辑器。我的程序通过启动 notepad.exe 进程打开为 .txt 文件。如果该进程退出,我想在主窗体中调用一个函数(以更新文本框)。 以下是我目前正在做的事情:

 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;
    }

GetRealPathByNode() 函数返回 TreeView 节点指向的文件的完整路径字符串。 DisplayText() 从节点指向的文件中读取文本并将其显示在富文本框中。

执行时,我的主窗体仍然可以按我的意愿使用,但是当进程终止(记事本关闭)时,它会抛出一个错误,指出函数 NotePadHasEnded 无法访问 treeView1 对象,因为它正在执行另一个过程。

如何创建一个进程,在我的主窗体中异步退出时调用一个函数?我知道当我使用 WaitForExit() 函数时它可以工作,但是我的表单会冻结并等到记事本关闭。我希望用户能够使用编辑器打开其他 txt 文件,并且当关闭一个编辑器时,我的 GUI 中的富文本框文本正在更新。

/编辑/ 现在解决了。 感谢伍德曼的回答,我更换了

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

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

【问题讨论】:

    标签: c# asynchronous process invoke exit


    【解决方案1】:

    您应该在NotePadHasEnded() 方法中使用Dispatcher.InvokeDispatcher.BeginInvoke 来切换到UI 线程,因为您只允许从UI 线程访问UI 对象。

    查看this post了解更多详情。

    【讨论】:

    • 我爱你 :) 在你引用的那篇文章中,我简单地使用了代码 sn-p this.Invoke((MethodInvoker)delegate() { NotePadHasEnded(node); });在表单中调用函数。现在完整的工作代码: editor.Exited += delegate { this.Invoke((MethodInvoker)delegate() { NotePadHasEnded(node); });这个改变就是它所需要的。谢谢。
    【解决方案2】:

    谷歌SynchronizationContext。发生错误是因为您的 UI 线程未与运行的第二个线程同步,然后编辑器被关闭。我找到了一些描述如何实现同步的示例:It's All About the SynchronizationContextExecutionContext vs SynchronizationContext。希望这对你有帮助;-)

    【讨论】:

      【解决方案3】:

      Exited事件发生在另一个线程中,你只能在自己的线程(称为UI线程)中访问UI控件。由于您使用的是 Windows 窗体,因此您应该使用 Control.Invoke 方法:

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

      还将NotePadHasEnded 的返回类型更改为void

      node.TreeView 用于访问Invoke 方法。您可以使用任何 UI 控件。如果代码位于表单中,您可以改用this

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-22
        • 2022-01-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多