2012-02-06 166 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秒才完成的时间。

相关问题