2012-02-06 162 views
1

我認爲這可能是以前被問過的,但我可能太愚蠢,無法理解給出的答案,所以我需要再次提問。使用來自線程的消息更新用戶界面

我有一個類對某些數據進行計算。在計算過程中,我希望通過數據檢查,狀態更新和數據線向UI輸出錯誤通知。我想實時做到這一點。從主應用程序中調用此函數時遇到的問題是,UI(在WPF中)凍結,直到所有計算完成,然後一次顯示所有消息。對於需要20到30秒完成的計算來說,這是有問題的。

所以我想使用線程。這幾乎是我第一次嘗試這種東西。我做的是這樣的:

private void btnStartCalculations_Click(object sender, RoutedEventArgs e) 
{ 
     //initialise parameters for run 
     calculator = new Calculator(...); 
     //Subscribe to calculator events for update 
     kasenCalculator.OnStatusUpdate += new Calculator.UpdateEventHandler(calculator_OnStatusUpdate); 
     //kasenCalculator.OnErrorLogUpdate += new Calculator.ErrorLogUpdateEventhandler(calculator_OnErrorLogUpdate); 
     //kasenCalculator.OnDataReadUpdate += new Calculator.DataReadUpdateEventHandler(calculator_OnDataReadUpdate); 

     //Run 
     Thread thread = new Thread(calculator.Run); 
     thread.Start(); 
} 

private void calculator_OnStatusUpdate(object sender, string Message) 
{ 
     Dispatcher.Invoke(DispatcherPriority.Normal, new Action<string>(UpdateStatusWindow), Message); 
} 

private void calculator_OnDataReadUpdate(object sender, string Message) 
{ 
     Dispatcher.Invoke(DispatcherPriority.Normal, new Action<string>(UpdateOriginalDataWindow), Message); 
} 

private void calculator_OnErrorLogUpdate(object sender, string Message) 
{ 
     Dispatcher.Invoke(DispatcherPriority.Normal, new Action<string>(UpdateErrorLog), Message); 
} 

private void UpdateStatusWindow(string Message) 
{ 
     TextBox statusWindow = this.txtStatus; 

     //Add status text 
     statusWindow.Text += Message + "\r\n"; 
     //Scroll to bottom of window 
     statusWindow.CaretIndex = statusWindow.Text.Length; 
     statusWindow.ScrollToEnd(); 
} 

private void UpdateOriginalDataWindow(string Message) 
{ 
     this.txtOriginalData.Text += Message; 
} 

private void UpdateErrorLog(string Message) 
{ 
     this.txtErrors.Text += Message + "\r\n"; 
} 

哪種類型的作品,該UI 得到更新,但它仍然不是非常敏感。我想知道是否應該使用BeginInvoke而不是Invoke,但是它只是保留所有的更新,直到計算完成並且我還可以在主線程中執行。

此外,即使這是運行,它實際上運行比我預期的要慢很多。

這是正確的方式去做我想做的事嗎?如果不是,那麼正確的方法是什麼?

回答

0

使用BeginInvoke一個異步調用到UI線程。您使用Invoke被阻止。


您的性能問題可能與字符串連接有關。你有很多日誌消息嗎?

也許使用ItemsControl並綁定一個ObservableCollection<string>它。然後只需將您的日誌消息添加到該集合

+0

感謝您使用ItemsControl的提示,這比添加到文本框要好得多。至於BeginInvoke ...當我用它替換Invoke時,我的UI不再刷新,我不明白爲什麼......它在等待什麼?有沒有辦法強制處理所有未完成的任務? – 2012-02-06 02:57:15

+0

對不起,我對此沒有任何進一步的瞭解。我無法想象爲什麼它不會更新給定的變化。 – 2012-02-07 15:02:32

+0

希望你不介意這個(很晚),但我很好奇你最終做了什麼?另外,'calculator_OnStatusUpdate'在工作線程上執行,所以在我看來,'Dispatcher'屬於那個線程而不是UI線程。 (注意:我沒有使用WPF。)指定正確的一種方法是:'this.Dispatcher.BeginInvoke(...)'。 – groverboy 2013-02-07 02:27:26

0

您正在做的正確。如果它是重要的使調度優先級高...

UpdateLayout(); 

這將迫使你的UI重新加載。確保這是在主UI線程上完成的。使用

BeginInvoke(); 

是異步的,我經歷過大概需要30秒才完成的時間。

相關問題