使用来自线程的消息更新UI

时间:2012-02-06 02:17:02

标签: .net wpf

我认为之前可能会问过这个问题,但我可能太傻了,无法理解所给出的答案,所以我需要再次提问。

我有一个类对某些数据执行计算。在计算过程中,我想将数据检查,状态更新和数据行的错误通知输出到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";
}

哪种方式有效,因为用户界面 正在更新,但它仍然不是很敏感。我想知道我是否应该使用BeginInvoke而不是Invoke,但这只是保留所有更新,直到计算完成运行,我也可以在主线程中执行。

此外,即使它正在运行,它实际上运行速度比我预期的要慢很多。

这是我正在做的事情的正确方法吗?如果没有,那么正确的方法是什么?

2 个答案:

答案 0 :(得分:0)

使用BeginInvoke对UI线程进行异步调用。您对Invoke的使用正在阻止。


您的性能问题可能与字符串连接有关。你有很多日志消息吗?

也许使用ItemsControl并将ObservableCollection<string>绑定到它。然后只需将您的日志消息添加到该集合

答案 1 :(得分:0)

你正确地做到了。如果重要的是使Dispatcher的优先级更高......

UpdateLayout();

这将强制您的UI重新加载。确保在主UI线程上完成此操作。使用

BeginInvoke();

是异步的,我经历过需要大约30秒才完成的时间。