WPF:模板实例化速度慢

发布于 2024-11-04 00:40:57 字数 600 浏览 0 评论 0原文

我有一个 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

街角卖回忆 2024-11-11 00:40:57

我的经验来自于开发 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.

花之痕靓丽 2024-11-11 00:40:57

这听起来与我遇到的问题类似。我在此处发布了修复程序:WPF UI 自动化问题。只是为了搜索者的利益而发布,因为它需要很长时间才能解决。

以下仅对链接答案进行评论,这是该帖子的关键:

我执行了以下操作:

  1. 下载的修补程序 - - http://archive.msdn.microsoft.com/KB978520(可能不是必需的)
  2. 已下载的修补程序 - - http://archive.msdn.microsoft.com/KB2484841(即使您使用的是 Windows 7 / .NET 4,这也是绝对必需的)
  3. 进一步改进了代码(验证导致对象过多)- < a href="https://stackoverflow.com/questions/2260616/why-does-wpf-style-to-show-validation-errors-in-tooltip-work-for-a-textbox-but-f">为什么在工具提示中显示验证错误的 WPF 样式对 TextBox 有效,但对 ComboBox 失败?

可能只需要数字 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:

  1. Downloaded Hotfix - - http://archive.msdn.microsoft.com/KB978520 (may not be required)
  2. Downloaded Hotfix - - http://archive.msdn.microsoft.com/KB2484841 (definitely required even if you have Windows 7 / .NET 4)
  3. Improved the code further (the validation was causing an excess of objects) - Why does WPF Style to show validation errors in ToolTip work for a TextBox but fails for a ComboBox?

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.

柠檬色的秋千 2024-11-11 00:40:57

数据模板中的用户控制并不是完全坏主意,但如果您渴望性能,那么您应该考虑切换到更轻的控制。例如,让 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.

佼人 2024-11-11 00:40:57
  • 尝试将所有资源向上移动
    尽可能地,最好是进入
    app.xaml
  • 检查是否可以使用 StaticResource
    而不是动态的,静态的
    快很多
  • 如果可能的话,尝试使用依赖关系
    虚拟机中的属性,特别是如果
    你同时拥有很多,或者如果
    他们有很多财产。这将使 wpf 不必进行大量反射。
  • Try moving all the resources up as
    far as they'll go, preferably into
    app.xaml
  • Check if you could use StaticResource
    instead of dynamic ones, static ones
    are alot faster
  • If possible, try using depedency
    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.
梦里兽 2024-11-11 00:40:57

您提到您正在使用包含 100 行的 DataGrid。性能问题的一个可能的罪魁祸首是您使用的任何数据网格都没有进行虚拟化,因此您的可视化树是巨大的。

通常,WPF 屏幕中较长的启动时间意味着较大的可视化树。

我不确定您是否每行使用一个数据模板,或者某些绑定列的第三方网格,或者什么 - 但假设您有 8 列带有控件。根据您的网格/验证/等,这可能是每行 20-60 个项目的可视化树。如果您有一个组合框,那么下拉列表中的每个项目也可以按行创建。

要解决这个问题,只需观察细节,并随时采取措施:

  1. 尽可能使用虚拟化控件。这意味着在列表控件内使用虚拟化堆栈面板,并确保您的第 3 方控件也能做到这一点(许多库存 WPF 控件现在默认情况下都这样做)。
  2. 不要过度使用用户控件、复合控件等。增加深度会增加时间,并放入额外的可视化树数据模板或其他重复区域的深度会快速增加。
  3. 如果所有其他方法都失败,请显示一个简单的屏幕并通过代码添加控件以提高感知性能

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:

  1. Use a virtualizing control as much as possible. This means using a virtualizingstackpanel inside list controls, and making sure your 3rd party controls do as well (many stock WPF controls do now by default)
  2. Do not overuse UserControls, composite controls, etc. Adding depth adds time, and putting in extra visual tree depth in a datatemplate or other repeated area adds up fast.
  3. If all else fails, show a simple screen and add controls through code to improve perceived performance
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文