2012-01-03 77 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

相關問題