【问题标题】:Right way to continuously update the UI持续更新 UI 的正确方法
【发布时间】:2017-11-01 07:24:25
【问题描述】:

假设客户端应用程序几乎实时地从服务器获取数据。根据检索到的数据持续更新 UI 的更有效方法是什么。考虑多个 xaml 控件,例如显示数字的文本。只要应用程序正在运行,它们就会更新。除非用户决定,否则它们永远不会停止。 (假设按下停止按钮或退出应用程序) 下面我有一个使用 async 和 await 关键字的简单示例。这对我的场景来说是个好方法吗?或者例如 BackgroundWorker 会是更好的方法?

private async void Button_Click_Begin_RT_Update(object sender, RoutedEventArgs e)
{
    while(true)
        textField1.Text = await DoWork();
}

Task<string> DoWork()
{
    return Task.Run(() =>
    {
        return GetRandomNumberAsString();
    });
}

*为了简单起见,我在示例中使用代码隐藏而不是 mvvm

【问题讨论】:

  • 自从我使用 WPF 已经有一段时间了,但我认为绑定到 DependencyProperty 是要走的路。这 2 个帖子应该让你朝着正确的方向分流:stackoverflow.com/questions/19981966/…, stackoverflow.com/questions/5824600/…
  • WPF 背后的核心思想是使用数据绑定和视图模型类,以便您永远直接在代码中调用控件。因此,如果我是你,我会创建一个 viewmodel 类,实现INotifyPropertyChanged 接口,将属性绑定到相关控件,然后使用 async Tasks 更新 viewmodel 类实例。
  • @mcy 为简单起见,我没有基于 MVVM 编写代码。但是我确实在我的项目中使用了 mvvm。
  • @gts13 好的。 Task vs BackgroundWorker 是一个引起很多关注的话题,你可能会发现像blog.stephencleary.com/2013/09/…stackoverflow.com/questions/12414601/… 这样的好帖子,我个人几乎所有时间都选择Task
  • @gts13 你已经有了解决方案。要么它非常适合你,在这种情况下,你没有问题,或者它不是,你需要具体说明它是如何无法满足你的需求的。

标签: c# wpf xaml


【解决方案1】:

如果您的 GetRandomNumberAsString() 至少需要 15 毫秒才能完成,那么您的代码或多或少是可以的。

如果所需的时间少于此,并且您希望最小化更新延迟,即您不想只是等待,您可能希望 (1) 将您的每次操作 Task.Run 替换为完全运行的无限循环后台线程 (2) 在该循环中实现节流机制,并且仅在 30-60Hz 左右更新您的 GUI(例如使用 Dispatcher.BeginInvoke())。

附:您更新 GUI 的确切机制(数据绑定 + INotifyPropertyChanged,或直接在您的代码中)与性能无关。

更新:这里是示例(未经测试)

static readonly TimeSpan updateFrequency = TimeSpan.FromMilliseconds( 20 );
void ThreadProc()
{
    Stopwatch sw = Stopwatch.StartNew();
    while( true )
    {
        string val = GetRandomNumberAsString();
        if( sw.Elapsed < updateFrequency )
            continue;   // Too early to update
        sw.Restart();
        Application.Current.Dispatcher.BeginInvoke( () => { textField1.Text = val; } );
    }
}

【讨论】:

  • 能否提供一些示例代码或链接来看看,尤其是“循环中的节流机制”对我来说有点棘手
  • 我有一台 75Hz 的显示器。有些人有 144Hz 的显示器。理想情况下,您的 UI 在每个绘制周期都会更新。
  • @IanBoyd 对于对延迟非常敏感的应用,CompositionTarget.Rendering 确实更好。但正确实施更难。该事件每帧可能会被调用多次,如果您的数据自上次调用以来发生了变化,您只需要更新 GUI。对于大多数应用程序,~30-50Hz 的更新限制是可以的。
  • “应用程序”不包含“当前”的定义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多