WPF:模板实例化速度慢
我有一个 WPF 应用程序,它很慢。
它不是渲染。首先,渲染非常简单,其次,我用 WPF Performance Toolkit 查看了它 - 什么都没有。
在我自己的代码中不。首先,单元测试运行得很快,其次,如果我用空白模板替换所有数据模板,一切都会运行得很快。
到目前为止,看起来最慢的部分是模板实例化。也就是说,当您启动应用程序并打开一些复杂的屏幕时,需要大量时间。我所说的“很多”是指“很多”。有时可能长达 3-5 秒 - 例如,当数据网格有 100 行时。但是,当您转到另一个选项卡,然后返回到同一屏幕时,它会快速打开(只要其视图模型保持不变)。
这非常烦人,不仅因为它很慢,而且因为我对此无能为力。如果我对速度有一定的控制,也许我可以显示一些“正在打开,请稍候”消息或其他内容......
此外,当我查看其他一些 WPF 应用程序(最值得注意的是,ILSpy ),尽管数据量很大,但它们的工作速度似乎相当快。这让我相信我可能做错了什么。但我不知道从哪里开始。
有什么想法吗?有哪些经典错误?有什么建议吗?
I have a WPF application, and it's slow.
It is NOT the rendering. Firstly, the rendering is quite simple, and secondly, I looked at it with WPF Performance Toolkit - nothing.
It is NOT in my own code. Firstly, the unit tests work fast, and secondly, if I replace all DataTemplates with blank ones, everything works fast.
So far, it looks like the slow part is template instantiation. That is, when you start the application, and open some complicated screen, it takes a lot of time. And by "a lot" I mean "a lot". Sometimes can be as much as 3-5 seconds - for example, when there's a datagrid with 100 rows. But when you go to another tab, and then go back to that same screen, it opens fast (as long as its viewmodel stays put).
This is very annoying not just because it's slow, but because I can't do anything about it. If I had some control over the slowness, I could, maybe, display some "opening, please wait" message or something...
Besides, when I look at some other WPF applications (most notably, ILSpy), they seem to work reasonably fast, despite the large amounts of data. This makes me believe that I'm probably doing something wrong. But I have no idea where to start.
Any ideas? Any classic mistakes? Any tips?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我的经验来自于开发 WPF 思维导图应用程序 NovaMind
几个月前,我们将中间层完全重写为解决我们遇到的性能问题。简而言之,创建用户控件似乎速度很慢。不幸的是,我找不到一种很好的方法来分析性能,因为 WPF Performance Suite 和 ANTS Profiler 等商业应用程序都没有为您提供有关 WPF 过程这一部分的任何详细信息。 (当时我问了这个问题)
我们通过反复试验来手动测试我们的应用程序,删除了部分用户控件,看看到底是什么罪魁祸首。
最终我们通过完全重写控件解决了性能问题。我们还大幅降低了视觉树的复杂性。在重写之前,我们最常用的用户控件之一,当用 Snoop 检查时,由 61 个不同的东西组成,现在只有 3 个。只要有可能,我们只根据需要将东西添加到可视化树中。 (正如您在 XAML 中所知,即使将内容设置为 Collapsed,也需要首先创建它们)。
最后我们被迫编写自己的富文本渲染控件,因为内置的 RichtextBox 速度慢得离谱,而且 RichtextBox 的可视化树非常复杂。
我不知道这是否适用于您的情况,但我建议您调查您的用户控件并查看它们是否复杂。也许你有可以修剪的东西。
容易实现的成果是很少可见或可以以懒惰的方式创建的部分。必要时,您可以从代码隐藏中创建这些部分,而不是将它们放在 XAML 中。这应该对你有很大帮助。
否则,如果可能的话,虚拟化是您的朋友。不幸的是,在我们的例子中,我们无法做到这一点。
My exerience comes from working on the WPF mind mapping application NovaMind
A couple of months ago we completely rewrote our intermediate layer to solve the performance issues we had experienced. In a nutshell, creating our user controls seemed to be way to slow. Unfortunately I couldn't find a great way to profile the performance as neither the WPF Performance Suite nor commercial applications such as ANTS Profiler give you any detailed information on this part of the WPF process. (I asked this question back then)
We resorted to manually test our application by trial and error and removed parts of our user controls to see what exactly is the culprit.
In the end we solved the performance issues by completely rewriting our controls. We also cut down on the complexity of our visual tree dramatically. Before the rewrite, one of our most used user controls, when inspected with Snoop, consisted out of 61 different things, now there are only 3. Wherever possible we only added things to the visual tree on demand. (As you know in XAML even when you set things to Collapsed, they need to be created first).
Finally we were forced to write our own rich text rendering control as the built in RichtextBox is ridiculously slow and the visual tree of the RichtextBox is quite complex.
I don't know if this will apply to your situation but I would recommend that you investigate your user controls and see if they are complex. Maybe you have things that you could trim.
Low hanging fruits would be parts that are only rarely visible or can be created in a lazy manner. You could create these parts from code behind when necessary rather than having them in XAML. This should help you a lot.
Otherwise virtualization is your friend, if possible. In our case we couldn't do that unfortunately.
这听起来与我遇到的问题类似。我在此处发布了修复程序:WPF UI 自动化问题。只是为了搜索者的利益而发布,因为它需要很长时间才能解决。
以下仅对链接答案进行评论,这是该帖子的关键:
我执行了以下操作:
可能只需要数字 3,但它有效。只是在这里发帖,这样人们就不会失去我在内存分析器等中失去的日子。
This sounds similar to a problem i was having. I posted the fix here: WPF UI Automation issue . Just posting for the benefit of searchers, as it took ages to resolve.
Following comment on link only answer, here is the crux of that post:
I did the following:
It may be that only Number 3 was required, but it worked. Just posting here so people dont lose the days I lost in memory profilers etc.
数据模板中的用户控制并不是完全坏主意,但如果您渴望性能,那么您应该考虑切换到更轻的控制。例如,让 UserControl 只托管 TextBox 是非常糟糕的主意,因为 UserControl 由 ContentControl 组成,ContentControl 托管 ContentPresenter,ContentPresenter 将托管 TextBox,因此如果您注意到您的可视化树,它具有三个新的 UI 元素层。减少视觉树肯定会提高性能。
最有可能的是,我建议创建自定义控件,它可能是一个全新的控件,具有很少的依赖属性,可以与您想要呈现的数据相关,并且您可以在 generic.xaml 中拥有自己的自定义模板。其次,您可以简单地从现有控件派生一个控件,并在 generic.xaml 中重新定义其默认模板。
这种方法肯定会更好,因为您将减少视觉树,从而减少视觉状态管理器的工作。
更改主题或模板会比更改托管内容的元素慢。并让元素在其自己的通用资源字典中具有默认模板。
User Control in your data template, is not completely bad idea but if you crave for performance then you should consider switching to lighter control. For example, having a UserControl just hosting a TextBox is very bad idea, as UserControl is made up of ContentControl, ContentControl hosts ContentPresenter and ContentPresenter will host TextBox so if you notice your Visual Tree, it has three new layer of UI Elements. Reducing Visual Tree will certainly improve the performance.
Most likely, I would suggest creating Custom Controls that may be a completely a new control having few dependency properties that can relate to data you want to present and you can have its own custom template in generic.xaml. Second, you can just simply derive a control from existing controls and redefine its default template in generic.xaml.
This approach will certainly work better as you will be reducing your Visual Tree, thus reducing Visual State Manager's job.
Changing theme or template will be slower then changing the element that hosts content. And let the element have the default template in its own generic resource dictionary.
尽可能地,最好是进入
app.xaml
而不是动态的,静态的
快很多
虚拟机中的属性,特别是如果
你同时拥有很多,或者如果
他们有很多财产。这将使 wpf 不必进行大量反射。
far as they'll go, preferably into
app.xaml
instead of dynamic ones, static ones
are alot faster
properties in your VMs, especially if
you have alot of them at once or if
they have alot of properties. That will keep wpf from having to do a bunch of reflection.
您提到您正在使用包含 100 行的 DataGrid。性能问题的一个可能的罪魁祸首是您使用的任何数据网格都没有进行虚拟化,因此您的可视化树是巨大的。
通常,WPF 屏幕中较长的启动时间意味着较大的可视化树。
我不确定您是否每行使用一个数据模板,或者某些绑定列的第三方网格,或者什么 - 但假设您有 8 列带有控件。根据您的网格/验证/等,这可能是每行 20-60 个项目的可视化树。如果您有一个组合框,那么下拉列表中的每个项目也可以按行创建。
要解决这个问题,只需观察细节,并随时采取措施:
You mention you are using a DataGrid with, say, 100 rows. A likely culprit of your perf problems is that whatever datagrid you are using isn't doing virtualization, and so your visual tree is gigantic.
Normally, long startup time in WPF screens points to a large visual tree.
I'm not sure if you're using a datatemplate per row, or some 3rd party grid that binds columns, or what - but lets say you have 8 columns with controls. Depending on your grid/validation/etc, this could be a visual tree of 20-60 items per row. If you have a combobox, then each item in the dropdown may be created per row as well.
To fix this just takes watching the details, and taking measures as you go: