这段代码是如何在不同的线程中执行的?

Val*_*tor 2 .net c# multithreading winforms

在Windows窗体项目中,我有一个按钮处理程序,可以在记事本中打开文件进行编辑.一旦记事本关闭,我调用一个函数RefreshTextBox()来解析文本文件并根据值更新TextBox.以下是打开记事本并在关闭时调用refresh方法的方法:

private void button_Click(object sender, EventArgs e)
    {
            Process p = new Process
            {
                EnableRaisingEvents = true,
                StartInfo =
                {
                    FileName = "NOTEPAD.EXE",
                    Arguments = _path,
                    WindowStyle = ProcessWindowStyle.Maximized,
                    CreateNoWindow = false
                }
            };

            p.Exited += (a, b) =>
            {
                RefreshTextBox();
                p.Dispose();
            };

            p.Start();
    }
Run Code Online (Sandbox Code Playgroud)

和刷新文本框的代码:

private void RefreshTextBox()
    {
        using (StreamReader reader = File.OpenText(_appSettingsPath))
        {
            string text = reader.ReadToEnd();

            // Code to parse text looking for value...

            // InvalidOperationException thrown here:
            textBox.Text = reader.Value.ToString();
        }
    }
Run Code Online (Sandbox Code Playgroud)

这会引发一个异常,试图从一个创建它的线程以外的线程更新Control.我很难理解为什么.我不会在新的任务或背景工作者或类似的事情中这样做.显然,记事本正在另一个线程中运行,但刷新方法直到它的进程退出后才会被调用.

编辑:我应该补充一点,在Visual Studio(作为管理员)中进行调试时,此错误会抛出致命异常弹出窗口.它自己运行应用程序时不会显示弹出窗口,要么是静默吞下,要么就不会出现异常.

sum*_*mar 6

根据文档,如果SynchronizingObject未设置Process ,它将在系统线程池中执行exited事件以避免这种情况并在UI线程中运行该事件处理程序,您需要将其设置SynchronizingObject为Form Instance

当SynchronizingObject为null时,将在系统线程池的线程上调用处理Exited事件的方法.有关系统线程池的更多信息,请参阅ThreadPool.

如果你设置

p.SynchronizingObject = WindowsFormName;
Run Code Online (Sandbox Code Playgroud)

然后它将在同一个线程中运行,否则它将在系统线程池线程中执行,这将导致交叉线程异常.

MSDN参考