提高大型项目c#WPF XAML的性能



我们公司有一个用C#+WPF+XAML编写的产品(程序)。这对我们来说是一个相当重要的程序,我们的许多客户都安装了它。但在切换到Framework 4.7.2之后,我们注意到性能出现了严重的下降。然后我们改到了4.8版本,但程序仍然运行得很慢,尤其是视觉部分。

在我们的程序中,我们显示来自大量传感器(运动传感器、温度、光量等)的数据。我们不断接收我们处理的新数据,保存到SQL Server 2014/2017数据库中,然后客户端程序将这些数据可视化。

服务器部分和通信虽然很复杂,但在功能不太强大的计算机上也能很好地工作。但我们在客户监视器上显示数据时遇到了一个很大的问题。

该程序的结构如下:客户端绘制他想要查看这些数据的位置。例如,他有一个黑色的背景,用线条画他的工厂。在这个工厂的不同地方都有传感器,他把它们画在这些地方。然后他开始扫描,看到他画标签的数据结果。当数据很少时,这不是很明显,但当数据很多时,在数据之间移动鼠标会被禁止,客户端看到程序不断减慢,他需要等待几秒钟,用鼠标移动一些,然后再次等待程序响应。如果你同时做了几件事,那么程序就会冻结。事实并非如此,但人们的感觉是,该程序现在将停止工作。

我试着使用调试和CPU和RAM的测量,但它实际上对我没有任何帮助。数据通常通过web服务从服务器下载到客户端程序,并根据需要占用尽可能多的内存。很难以某种方式优化它。但当我们开始向用户显示这些数据时,一切都开始变得非常糟糕。如何优化数据可视化,让用户继续冷静地使用程序?愿意接受任何建议。

我所做的,对改进DataGrid表中的虚拟化有所帮助。这对用户来说有点好,但这还不够,你还需要其他东西,尤其是绘制并在不同地方显示带有数据的标签的部分。

根据我的经验,wpf不适合可视化大量数据。这对于创建一个花哨的UI来说很好,但随着对象数量的增加,性能会急剧下降。我尝试了从缓存到冻结对象的所有方法,得出的结论是我只是选择了错误的技术。它没有正确利用你的GPU。

你可以尝试转换为UWP,这可能会有所帮助。

话虽如此,以下是一些你也可以尝试的技巧:

  1. 简化可视化树性能问题的常见来源是深度和复杂的布局。保持XAML标记简单而肤浅尽可能。当UI元素在屏幕上绘制时,"布局过程"是为每个元素调用两次(一次测量过程和一次排列过程)。布局过程是一个数学密集型过程——元素中的子元素数需要进行计算。

  2. 虚拟化项目控件如前所述,复杂而深入的可视化树会导致更大的内存占用和更慢的速度表演项目控件通常会增加性能问题深度视觉树,因为它们没有被虚拟化。这意味着他们不断为中的每个项目创建和销毁控制相反,使用VirtualizingStackPanel作为项目主机使用VirtualizingStackPanel.IsVirtualization并设置VirtualizationMode to Recycling以便重复使用物品容器而不是每次都创建新的。

  3. 偏爱StaticResources而非DynamicResources StaticResources通过查找对已定义的资源。该资源的查找行为是与编译时查找相同。DynamicResources将创建临时表达式,并将资源查找推迟到请求的资源值是必需的。的查找行为资源与运行时查找相同,这会带来性能影响只要可能,请始终使用StaticResource。

  4. 笔刷而非元素上的不透明度如果使用笔刷设置元素的"填充"或"笔划",最好将"不透明度"设置为Brush,而不是设置元素的"不透明度"属性。当你修改元素的"不透明度"属性,会导致WPF创建临时表面,从而导致性能打击。

  5. 避免使用Run设置文本属性避免在TextBlock中使用Run,因为这会导致更高的性能密集型活动如果使用Run设置文本属性,请设置而是直接在TextBlock上。

  6. 支持StreamGeometry而不是PathGeometry StreamGeometrys对象是PathGeometry的一个非常轻量级的替代对象。StreamGeometry针对处理许多PathGeometry对象进行了优化。它与使用相比,消耗的内存更少,性能更好许多PathGeometry对象。

  7. 使用缩小的图像大小如果您的应用程序需要显示较小的缩略图,请考虑创建缩小的图像版本。默认情况下,WPF将加载您的图像并将其解码为完全大小。这如果加载已满,可能会导致许多性能问题图像,并在控件(如项目控制。如果可能将所有图像组合成单个图像,例如由多个图像组成的胶片条。

  8. 降低BitMapScalingMode默认情况下,WPF使用高质量的图像重新采样算法,有时会消耗系统导致帧速率下降并导致动画结结巴巴。相反,请将BitMapScalingMode设置为LowQuality从"质量优化"算法切换到"速度优化"算法。

  9. 使用和冻结可冻结对象可冻结对象是一种特殊类型的对象,有两种状态:未冻结和冻结。冻结对象时例如Brush或Geometry,则不能再对其进行修改。极冷的对象尽可能提高应用程序的性能并减少其存储器消耗。

  10. 修复绑定错误绑定错误是WPF应用程序中最常见的性能问题。每次发生绑定错误时,您的应用程序在尝试解析绑定和将错误写入跟踪日志。正如你所能想象的绑定错误越多,应用程序的性能打击就越大拿花点时间查找并修复所有绑定错误。使用DataTemplates中的RelativeSource绑定是导致绑定的主要原因错误,因为绑定通常在DataTempate已完成初始化。避免使用RelativeSource.FindAncestor不惜一切代价。相反,定义一个附加属性,并使用属性继承将值向下推送到可视化树,而不是查找视觉树。

  11. 避免数据绑定到Label.Content属性如果您使用Label数据绑定到String属性,这将导致表演这是因为每次更新String源时,旧的字符串对象将被丢弃,并创建一个新的字符串。如果标签的内容是简单文本,请将其替换为TextBlock并改为绑定到Text属性。

  12. 将ItemsControls绑定到IList而不是IEnumerable当数据将ItemsControl绑定到IEnumeraable时,WPF将创建一个包装类型IList,对性能产生负面影响创建第二个对象。而是直接绑定ItemsControl以避免包装器对象的开销。

  13. 使用NeutralResourcesLanguage属性使用Neutral ResourcesLanguageAttribute告诉ResourceManager中性区域性是并避免不成功的附属程序集查找。

  14. 在单独的线程上加载数据性能问题、UI冻结和应用程序停止响应的一个常见来源是加载方式您的数据。确保将数据异步加载到单独的线程,以免重载UI线程。正在上加载数据UI线程将导致非常差的性能和整体糟糕最终用户体验。多线程应该是每个WPF的特点开发人员正在他们的应用程序中使用。

  15. 小心内存泄漏在大多数WPF应用程序中,内存泄漏是导致性能问题的首要原因。它们很容易拥有但是可能很难找到。例如,使用DependencyPropertyDescriptor.AddValueChanged可能导致WPF框架,以强烈引用事件的来源在您手动调用之前不会被删除DependencyPropertyDescriptor.RemoveValueChanged。如果您的视图或行为依赖于从对象或ViewModel引发的事件(如INotifyPropertyChanged),弱订阅或制作请确保您正在手动取消订阅。此外,如果您绑定到ViewModel中未实现的属性INotifyPropertyChanged,很可能是内存泄漏。

最后,一个额外的小费。有时当你遇到性能问题时很难确定到底是什么导致了问题。我建议使用应用程序性能探查器来帮助识别这些性能瓶颈发生在代码库中的位置。有很多探查器选项可供选择。有些是付费的,还有一些是免费的。我个人使用最多的是诊断直接内置到Visual Studio 2019中的工具。区块报价

来源:https://dzone.com/articles/15-wpf-performance-tips-for-2019

相关内容

  • 没有找到相关文章

最新更新