C# 文本框仅在其他线程完成后更新

C# 文本框仅在其他线程完成后更新,c#,winforms,multithreading,process,C#,Winforms,Multithreading,Process,几天来,我一直在想如何使用makeconsoleupdate文本框作为它的执行工具。我得出的结论是,线程对于同时运行窗体和控制台进程是绝对必要的。进程本身是独立的程序,所以我使用标准输出从中获取信息,如果我不需要它在工作时更新textbox,那就太好了,但问题是它只在进程执行后更新,尽管事实上我使用多线程 是为运行进程并处理输出的函数以及用于在线程和锁之间交换信息的字符串生成委托的开始: private static readonly object _locker = new objec

几天来,我一直在想如何使用makeconsoleupdate文本框作为它的执行工具。我得出的结论是,线程对于同时运行窗体和控制台进程是绝对必要的。进程本身是独立的程序,所以我使用标准输出从中获取信息,如果我不需要它在工作时更新textbox,那就太好了,但问题是它只在进程执行后更新,尽管事实上我使用多线程

是为运行进程并处理输出的函数以及用于在线程和锁之间交换信息的字符串生成委托的开始:

    private static readonly object _locker = new object();
    volatile string exchange = "";
    delegate void CallDelegate(string filename);
函数本身如下:

    public void CallConsole(string filename)
    {
        Thread.CurrentThread.Name = "ProccessThread";
        Thread.CurrentThread.IsBackground = false;
        Process p = new Process();
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.FileName = filename;
        if (checkBox1.Checked)
            p.StartInfo.CreateNoWindow = true;
        string output;
        p.Start();
        while (!p.HasExited)
        {
            lock (_locker)
            {
                output = p.StandardError.ReadToEnd();
                if (output.Length != 0)
                {
                    exchange = output;
                    Thread.Sleep(100);
                    MessageBox.Show(output);
                }
                output = p.StandardOutput.ReadToEnd();
                exchange = output;
                System.Threading.Thread.Sleep(100);
            }
        }
    }
这是点击按钮后程序的执行情况

    private void button1_Click_1(object sender, EventArgs e)
    {
        textBox2.Text = "";
        //Thread.CurrentThread.Name = "Main";
        CallDelegate call = new CallDelegate (CallConsole);
        IAsyncResult tag = call.BeginInvoke(textBox1.Text, null, null);
        button1.IsAccessible = false;
        while (!tag.IsCompleted)
        {
            string temp = "";
            lock (_locker)
            {
                Thread.Sleep(50);
                if (exchange.Length != 0)
                {
                    temp = exchange;
                    exchange = "";
                }
            }
            if (temp.Length != 0)
                textBox2.Text = textBox2.Text + temp;
        }
        call.EndInvoke(tag);
        button1.IsAccessible = true;
    }
注: textbox1是文件路径 textbox2是只读多行文本框


你知道为什么只有在CallConsole完成后才更新它吗?

一般问题:你在
按钮1\u Click\u 1
中循环,有效地阻止了UI线程。防止处理其他事件,包括重绘等

你不应该那样做;相反,如果您想要轮询某些内容,请设置一个计时器来执行轮询,从而允许UI在“空闲”时间内处理事件

更直接的问题:您正在从未完成的进程中调用读取器上的
ReadToEnd
。这(我相信)会一直阻碍,直到过程完成。(在它完成之前,阅读器本身没有“结束”)这意味着您有一个线程持有锁并阻塞,直到进程完成——然后您尝试在UI线程中获取该锁


我还建议从降低轮询依赖性开始—查看
进程
类上的事件,并尝试处理这些事件,而不是在单独的线程中阻塞。当其中一个事件发生时,您可以发回UI线程(使用
Control.Invoke
)以更新UI。。。然后无需轮询。

一般问题:您在
按钮1\u单击1
中循环,有效地阻止了UI线程。防止处理其他事件,包括重绘等

你不应该那样做;相反,如果您想要轮询某些内容,请设置一个计时器来执行轮询,从而允许UI在“空闲”时间内处理事件

更直接的问题:您正在从未完成的进程中调用读取器上的
ReadToEnd
。这(我相信)会一直阻碍,直到过程完成。(在它完成之前,阅读器本身没有“结束”)这意味着您有一个线程持有锁并阻塞,直到进程完成——然后您尝试在UI线程中获取该锁


我还建议从降低轮询依赖性开始—查看
进程
类上的事件,并尝试处理这些事件,而不是在单独的线程中阻塞。当其中一个事件发生时,您可以发回UI线程(使用
Control.Invoke
)以更新UI。。。那就不需要投票了。

我认为乔恩·斯基特是发生在某某和C#身上最好的人之一。我认为乔恩·斯基特是发生在某某和C#身上最好的人之一。