2013-03-14 32 views
0

我有一個生活在任務欄區域的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方式」?

+5

你正在提交GUI編程的偉大之一,你用你的while循環阻塞了UI線程。它並沒有完全死亡,因爲在UI線程上調用WaitOne()是非法的,CLR會抽取一個消息循環來保持它的活性。你將需要擺脫while循環。容易做到,Process類有一個Exited事件。 – 2013-03-14 22:04:28

回答

0

您的代碼在繁忙等待循環檢查IsComplete標誌異步但隨後開始的方法塊。這不是使用代表的正確方法。

而不是忙等待,你應該傳遞一個回調函數BeginInvoke,當委託完成時將被調用。這已經在文檔中介紹過了。檢查「在異步調用完成時執行回撥方法」中的

在你的情況,你會寫:

del.BeginInvoke(port, baud, timeout, job, new AsyncCallBack(MyMethod), null); 

這裏的MyMethod是將處理調用的結果的方法。

1

嘗試在主線程中執行此:

ProcessStartInfo psi = new ProcessStartInfo(); 
Thread processStarter = new Thread(delegate() 
{ 
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; 
process.Start(); 
process.WaitForExit(job.Timeout); 
//call methods that deal with the files here 
}); 
processStarter.IsBackground = true; 
processStarter.Start(); 
相關問題