WPF元素事件处理程序中的UI更新

bra*_*her 7 wpf user-interface multithreading event-handling

WPF中的UI更新存在问题.

我有这样的代码:

    private void ButtonClick_EventHandler(object sender, RoutedEventArgs e)
    {
        Label.Visibility = Visibility.Visible;
        TextBox.Text = "Processing...";

        LongTimeMethod(); //some long operation
    }
Run Code Online (Sandbox Code Playgroud)

问题是,在LongTimeMethod结束(即事件处理程序结束)之前,不会更改Label.Visibility和TextBox.Text.

到目前为止我解决了这个问题:

    private void ButtonClick_EventHandler(object sender, RoutedEventArgs e)
    {
        Label.Visibility = Visibility.Visible;
        TextBox.Text = "Processing...";

        Dispatcher.BeginInvoke(new Action(LongTimeMethod), 
            DispatcherPriority.Background);
    }
Run Code Online (Sandbox Code Playgroud)

没有使用调度程序调用还有其他解决方案吗?调用this.UpdateLayout()没有帮助.

Ste*_*rex 5

随着Dispatcher.BeginInvoke你还在使用UI线程LongTimeMethod()。如果这不是必需的(即它正在执行某种后台处理),我建议使用 TPL 在后台线程上运行它:

private void ButtonClick_EventHandler(object sender, RoutedEventArgs e)
{
    Label.Visibility = Visibility.Visible;
    TextBox.Text = "Processing...";

    Task.Factory.StartNew(() => LongTimeMethod())
        .ContinueWith(t =>
        {
            Dispatcher.BeginInvoke((Action)delegate()
            {
                TextBox.Text = "Done!";
            });
        });

}
Run Code Online (Sandbox Code Playgroud)

使用此方法,长时间运行的方法在后台线程上处理(因此 UI 线程将可以自由地继续呈现并且应用程序不会冻结)并且您可以执行任何更改 UI 的操作(例如更新文本框文本)在Dispatcher后台任务完成时显示在 UI 上

  • @brain_pusher,如果 UI 线程正在执行长时间运行的操作,那么它将无法更新您设置的 UI 属性。通过使用`Dispatcher.BeginInvoke`,您是在说“在UI 线程上执行此操作,但不要*现在*”;当你完成你当前的任务时就去做吧”。这就是您看到更新后的 UI 的原因 (2认同)

Opt*_*eam 1

Visibility 和 Text 是由调度程序更新的依赖属性。您的解决方案绝对正确,但我的建议是异步执行。

另一方面,您可以在 WPF 中模拟 Application.DoEvents(请参阅文章)。