其他线程完成后,文本框仅更新

时间:2012-01-03 11:36:28

标签: c# winforms multithreading process

几天来,我一直在试图弄清楚如何使用make console update text-box作为执行。我得出结论,线程对于同时运行表单和控制台进程是绝对必要的。进程本身是独立的程序,所以我使用标准输出来获取信息,如果我不需要它更新文本框作为其工作,它会很好,但问题是它只在执行过程后更新事实上,我使用的是多线程。

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

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

这是在button_click

之后执行程序
    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 个答案:

答案 0 :(得分:7)

一般问题:您在button1_Click_1内循环,有效阻止了UI线程。这可以防止处理其他事件 - 包括重绘等。

你不应该这样做;相反,如果你想轮询一些东西,设置一个计时器来进行轮询,允许UI在“空闲”时间内处理事件。

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

我还建议让整个事情开始时更少依赖于轮询 - 查看Process类上的事件,并尝试处理这些事件而不是在单独的线程中阻塞。当其中一个事件发生时,您可以回发到UI线程(使用Control.Invoke)来更新UI ...然后 nothing 需要轮询。