我有一個生活在任務欄區域的Winforms應用程序。一個窗口打開了日誌輸出。在C#/ WinForms中調用外部進程會導致UI無響應。爲什麼?
現在,在我的組件(仍然在UI線程這裏)我需要調用一個外部進程,運行5-15分鐘,併產生文件。我需要等待進程退出並使用這些文件。
因爲我希望我的用戶界面響應(移動窗口等等)我實現了一個代理和我打電話用的BeginInvoke/EndInvoke會的過程:
private delegate int BeginCallDelegate(int port, int baud, int timeout, Job job);
private BeginCallDelegate del = null;
public IAsyncResult BeginCall(int port, int baud, int timeout, Job job)
{
del = new BeginCallDelegate(Call);
IAsyncResult iar = del.BeginInvoke(port, baud, timeout, job, null, null);
return iar;
}
調用代碼我輪詢的IAsyncResult與WaitOne的(),但請注意,用戶界面是極其反應遲鈍如果不是冷凍:
IAsyncResult a = agent.BeginCall(...); //BeginInvoke
while (!a.IsCompleted)
{
iar.AsyncWaitHandle.WaitOne(250);
//writing something to a textbox works here, but overall responsiveness is weak
}
agent.EndCall(iar); //EndInvoke
VS告訴我,外耳炎l進程在一個工作線程上啓動,但爲什麼這對我的UI響應沒有幫助?它不應該阻止調用線程
下面是啓動過程的代碼:
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "app.exe";
psi.Arguments = String.Format("blah blah", port, baud, timeout, job.FullName);
psi.CreateNoWindow = false;
psi.ErrorDialog = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo = psi;
if (!process.Start())
throw new Exception("The process cannot start.");
process.WaitForExit(job.Timeout);
提示:爲了測試,外部APP.EXE是一個虛擬應用程序,並沒有別的,但主題。睡眠(60000)。 CPU負載爲3%。
另一個問題:如何在不使用Begin/EndInvoke的情況下做到「TPL方式」?
你正在提交GUI編程的偉大之一,你用你的while循環阻塞了UI線程。它並沒有完全死亡,因爲在UI線程上調用WaitOne()是非法的,CLR會抽取一個消息循環來保持它的活性。你將需要擺脫while循環。容易做到,Process類有一個Exited事件。 – 2013-03-14 22:04:28