2012-01-03 33 views
1

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

正在委托运行过程和处理输出,以及串,我使用的线程和锁之间交换信息功能的开始:

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中是只读的多行TextBox

为什么只有CallConsole后的更新做任何想法?

回答

7

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

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

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

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

+0

我认为Jon Skeet是发生在SO和C#上的最好的事情之一。 – Burimi 2012-01-03 14:48:59

相关问题