在UI呈现时显示加载指示符

时间:2018-01-03 08:11:49

标签: c# wpf

将整个问题更新为更具体

我有一个WPF应用程序,在加载时,它显示一个循环加载指示器,而另一个线程从服务器获取数据并操纵数据。

这个WPF应用程序有一个ItemsControl,其中包含约500个项目,包含10个以上的不同模板。我有一个模板选择器,用于根据项目的属性确定要使用的模板。

我有一个复选框,用于显示和隐藏UI中每个项目中的某些文本块。当我选中该复选框时,UI将冻结10秒钟,然后再次使用文本块开始响应。如果我取消选中该复选框,它将冻结约7秒钟,然后文本块将消失。

我知道我应该使用虚拟化,但它对我不起作用,因为每个项目的高度都不相同。我已经尝试过"标准" VirtualizationMode,向下滚动时速度很慢,对我来说不可用,以及"回收"由于物品的高度不同,所以不会工作。

我希望显示加载指示器,而不是将UI冻结7-10秒。我不是在问加载应用程序时如何显示加载指示器,而是在UI忙于重新绘制时如何显示加载指示器。

请指教,谢谢!

1 个答案:

答案 0 :(得分:1)

IIRC有一些,但想一想 - 当UI即将渲染时,绘图区域很脏并准备好更新。更新即将发生。如果更新需要很长时间(比方说,3秒),那么即使你的eventhandler / viewmodel / etc对“我正在开始渲染”事件作出反应,你想要实际做什么?

显示忙碌指示器? 显示?那是一个变化。它会将相关区域标记为脏,但是某些内容已经很脏,重绘正在等待,并且需要很长时间(3s),对吧?因此,如果您显示/隐藏任何内容,它将在渲染完成后显示 。也就是说,您的忙碌指示器可能会在3秒后出现并立即隐藏。

当然,这与其他事情无关......当渲染开始时,你可以发送一个TCP数据包,播放声音,用自己独立的threds显示另一个窗口/表面(所以​​他们不会等到第一次渲染结束)等等。

我认为你真正需要做的是混合:

  • 优化创建和数据绑定
    • 不在UserControls构造函数中加载数据
    • 尽可能快地读取所有数据绑定属性,在getter中不进行数据库/网络访问等;返回NULL,触发后台任务,更新属性,并且即使数据可用也会更改
    • 尽可能使用OneWay甚至OneTime绑定
    • 不要过度使用事件,转换器,模板选择器等UI回调;如果他们真的需要,快点闪电
    • (...)
  • 努力限制UI元素的更改次数
    • 也许你不需要所有这些?
    • 也许你可以合并其中一些以获得相同的效果,用更少的UI对象?
    • 也许你可以缓存一些现成的元素,这样就不需要创建了它们?
    • 也许你可以缓存他们的视觉效果?意思是渲染位图缓存,所以WPF甚至不需要渲染它们,只是告诉GPU使用缓冲图像?
    • 如果在可滚动区域中显示了大量新的UI元素,您可以在UI或/和DATA元素上使用虚拟来仅显示那些真正可见的内容现在,并修剪掉视口之外的所有内容(WPF对此有一些很好的支持)
    • 也许您可以限制一次显示的UI元素数量?而不是显示繁忙的指标和大量的新元素并让它们全部显示在3s之后,可能显示忙碌指标和前100个元素,等待一段时间(或直到渲染),然后才开始抽取更多元素到显示(再次,不是所有的,因为可能繁忙的指标将动画,它会冻结..)?
    • (...)
  • 努力简化要展示的众多元素的UI模板,以便快速显示
    • 限制其深度(例如,将usercontrol>grid>scroll>listbox>panel>[items:usercontrol>grid>listbox>panel>[items:grid>textblock]的布局更改为usercontrol>grid>listbox>scrollpanel>[items:textblock]]
    • 限制对UI元素的更改量
    • 限制布局计算的数量(如果不需要,请不要更改尺寸,使用尺寸,边距等的常量值,而不是尽可能计算)
    • 使用renderTransforms而不是layoutTransforms,如果可能的话
    • 将复杂的画笔(甚至是VisualBrushes)用于复杂背景,而不是将它们构建为Canvas上的布局元素
    • 在那些数以万计的项目中,尽可能地限制绑定和增加资源的使用(意思是,XAML中的{StaticResource}等)。如果你显示10k不同颜色的元素,有时最好定义50个项目模板,颜色通过StaticResources设置(所以,redItemTemplate,greenItemTemplate,blueItemTemplate,..),而不是一个commonItemTemplate从itemViewModel绑定它的所有颜色
    • (...)
等等,这是初学者的基础知识。除了一些基本点,优化WPF实际上可能很难。下面进一步阅读,我从之前的经验中了解到的大多数文章,帮助我成功优化了许多应用程序:

现在,回答你的问题,虽然我仍然认为这不是正确的方法:

  • 检测渲染何时开始:只需使用event CompositionTarget.Render MSDN
  • 检测渲染何时结束:在计划渲染后,在Dispatcher上发送优先级为DispatcherPriority.ContextIdle MSDN的任务; source article