【问题标题】:Update UI control frequently with multiple threads使用多线程频繁更新 UI 控件
【发布时间】:2014-08-07 11:25:59
【问题描述】:

我有一个 DevExpress GridControl 单向绑定到视图模型中的表视图。大约有 20 个后台线程从数据库中查询数据并单独更新 tableview。对表视图的更新是带锁的,用于异步更新。 Dispatcher 用于刷新主 UI 线程。我还有另一个按钮可以通过 CancellationTokenSource 取消数据库和更新功能。

但是,当应用程序运行时,我必须多次单击取消按钮才能执行取消命令中的代码。换句话说,UI 主线程忙于刷新 GridControl 并阻塞了取消按钮。

有没有办法实现这个功能?

编辑:发现这个方法很有帮助等待 Dispatcher.Yield(DispatcherPriority.ApplicationIdle); 它只是让其他 UI 控件有机会执行。

创建一个可等待对象,该对象以异步方式将控制权交还给当前调度程序,并为调度程序提供处理其他事件的机会。 (MSDN)

【问题讨论】:

  • UI 线程忙的时候就忙了。也许您可以更有效地更新数据绑定数据集合?也许只是更新更改,而不是每次都更新整个集合?

标签: wpf binding


【解决方案1】:

AFAIK,UI代表用户界面,主要部分是用户用户不是机器人,它是一个人,它使用你的应用程序。您不需要在 UI 线程上如此频繁地查询数据更新。为什么数据库查询操作需要20个线程?您有一个 GridControl,它一次只能在屏幕上显示几行,20、50、100(不再)。所以,我建议你只有一个线程来从数据库中读取数据,并且每 2-5 秒执行一次,以便为 User 提供一些交互性。为此,TPL - 是不错的选择。将它与 CancellationToken 一起使用 - 是支持取消您的方案的好方法。在数据库查询之间,您可以执行以下操作:

while (true)
{
    myToken.ThrowIfCancellationRequested();
    // database query here

    myToken.WaitHandle.WaitOne(2000)
}

此外,在更新源集合之前,您可以使用以下内容:

GridControl.BeginDataUpdate();
//Update your source collection
GridControl.EndDataUpdate();

这将阻止 DevExpress 控件侦听 CollectionChanged 事件或任何其他事件,因为在每个添加/删除操作 DevExpress 调用 UpdateLayout() 方法,这并没有我们想要的那么快。

如果布局在任一方面无效,UpdateLayout 调用将重做整个布局。因此,您应该避免在元素树中的每个增量和微小更改之后调用 UpdateLayout。

【讨论】:

  • 我需要查询的数据库很多,所以我并行查询它们以提高速度。如果我更新 viewmodel 中的数据,如何调用 BeginDataUpdate/EndDataUpdate?
  • 您需要将 GridControl 传递给您的 ViewModel,这是一种简单的方法,但您可以说它破坏了您的 MVVM 模式(向 DevExpress 打个招呼)。另一种方法是停止引发集合的 CollectionChanged 和 PropertyChanged 事件以及集合元素,并且仅在更新周期完成时才执行此操作,引发 Reset 事件(有点烦人,但您的 MVVM 主义会得到满足)。此外,您还有更多其他选择来保存松耦合的 V 和 VM,但这是另一个问题
  • 对,“while (myToken.WaitHandle.WaitOne(2000))”是什么意思
  • 是的,我的错。片刻 - 你会看到编辑。
  • 是的,谢谢你的建议,但是我们需要阻塞线程2秒吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-26
相关资源
最近更新 更多