加载大量用户控件时出现性能问题
我的应用程序正在将一堆相同的用户控件加载到 ScrollPanel 中。问题是,这非常慢。
分析器显示瓶颈是 Application.LoadComponent()
方法,该方法是从我的用户控件的构造函数内部调用的。此方法的文档说此方法加载 XAML 文件。
问题是,如何使用 BAML 代替 XAML?如何才能确保用户控件的 XAML 在创建新实例时不会被一次又一次地解析?有没有其他方法可以更快地加载我的用户控件?
My application is loading a bunch of the same user control into a ScrollPanel
. The problem is, this is very slow.
The profiler shows that the bottleneck is the method Application.LoadComponent()
, which is called internally from the constructor of my user control. The documentation of this method says that this method loads XAML files.
The question is, how can I use BAML instead of XAML? How can I accomplish that the XAML for my user control must not be parse again and again when creating new instances from it? Is there another way to make loading my user controls faster?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
LoadComponent()
已经加载了.baml
,不用担心这一点问题。 Microsoft 故意这样做,是为了不让开发人员依赖baml
格式。展望未来,他们可以在不破坏任何现有应用程序的情况下改进格式。是的,还有其他方法可以让它运行得更快。第一个优化是UI 虚拟化。 WPF 已经附带了方便的 VirtualizingStackPanel。它与 ItemsControls 协同工作,并且有一定的限制(例如,如果您创建项目容器并自行添加它们,则会失去虚拟化,或者如果设置
ScrollViewer.CanContentScroll="False"
则会失去虚拟化再次)。要使用虚拟化,您可能需要重写应用程序以使用ItemsControl + DataBinding
样式(ListBox
已启用虚拟化)如果您觉得需要有关 UI 虚拟化的更多信息请参阅 Dan Crevier 的博客。
以及最后的建议。您可以尝试将用户控件重写为自定义控件。我的简单性能测试显示如下图。使用相同的可视化树创建 10K 控件所花费的时间:
希望这有帮助
LoadComponent()
already loads.baml
, don't worry about this bit of the question. Microsoft did this intentionally, to not let developers make dependencies onbaml
format. Going forward they can improve the format without breaking any existing applications.Yes, there are another ways of making it work faster. The first optimization to take is UI virtualization. WPF already comes with handy VirtualizingStackPanel. It works in tandem with ItemsControls, and has certain limitations (e.g. if you create items containers and add them by your own, you loose virtualization, or if you set
ScrollViewer.CanContentScroll="False"
you loose it again). To use virtualization you will probably have to rewrite your application to useItemsControl + DataBinding
style (ListBox
already has virtualization enabled)If you feel like you need even more information on UI virtualization refer to Dan Crevier's blog.
And final advice. You can try rewriting your UserControls to Custom Controls. My simple performance test showed the following figures. To create 10K controls with the same visual tree it took:
Hope this helps
当实例化用户控件时,调用链如下所示:
UserControl.Constructor
UserControl.InitializeComponent()
Application.LoadComponent()
XamlReader.LoadBAML()
根据我的经验,它的最终调用实际上一直消耗时间。这是加载 XAML 文件(以 BAML 格式存储)并将其转换为实际对象以供使用的步骤。
我发现了两种减少或消除此处所用时间的通用方法。
以下简单的重构很容易完成,在我处理过的情况下,加载时间可能会减少大约 75%(非常粗略!)通常您会开始使用如下内容:
典型的
UserControl
起点MyControl.xaml
文件:对应
MyControl.xaml.cs
文件:重构1:
Control
与xaml/xaml .cs 文件从该起点开始,将其修改为从
Control
而不是UserControl
派生,并显式设置ControlTemplate
:MyControl.xaml
文件:对应的
MyControl.xaml.cs
文件:无论出于何种原因,在我尝试过的所有示例中,仅执行此操作就减少了大约 75%(大约)的加载时间。这是一种非常快速且简单的重构,具有显着的优势。
Visual Studio 对 xaml / xaml.cs 的使用非常满意,尽管它有点不标准。
但请注意,XAML 仍将在控件的每个实例化中加载和处理。不过,这是可以避免的,请参阅下一节。
重构 2:使用资源字典的
Control
就性能而言,更好的方法是将
ControlTemplate
重构为资源字典。这完全消除了每个控件实例的 XAML 负载,并且(根据我的经验)几乎没有延迟。将原始
.xaml
文件替换为“MyControlResources.xaml
”,如下所示:此资源字典需要添加到
app.xaml< 中的合并字典中/代码>。
将原始
xaml.cs
文件替换为纯MyControl.cs
文件,其中包含:请注意,不再调用
InitializeComponent()
。样式系统用于应用XAML仅加载一次的控件模板。这是一个更实质性的重构,但仍然相对容易执行,因为通常需要很少的其他代码修改。最初由
ElementName
直接对顶级控件进行的绑定应更改为使用TemplateBinding
。您可以组织控制模板和以其他方式样式资源,这只是显示了一种直接对应于用户控件的原始代码组织的方法。我个人喜欢一个控件对应一个资源字典。
When a user control is instantiated the call chain is something like this:
UserControl.Constructor
UserControl.InitializeComponent()
Application.LoadComponent()
XamlReader.LoadBAML()
In my experience its the final call which actually consumes all the time. That is the step where the XAML file (stored in BAML format) is loaded and converted into actual objects for use.
I have found two general approaches to reducing or eliminating the time taken here.
The following simple refactoring is easy to do and in the cases I've worked on may reduce load time by about 75% (very roughly!) Typically you would start out having something like this:
Typical
UserControl
starting pointMyControl.xaml
file:Corresponding
MyControl.xaml.cs
file:Refactoring 1:
Control
with xaml/xaml.cs filesFrom that starting point, modify it to derive from
Control
instead ofUserControl
and set theControlTemplate
explictly:MyControl.xaml
file:Corresponding
MyControl.xaml.cs
file:For whatever reason in all the examples I had tried, just doing this knocked off about 75% (roughly) of the load time. This can be a very quick and easy refactoring that has a substantial advantage.
Visual Studio is perfectly happy with this xaml / xaml.cs usage even though its a little nonstandard.
However note that the XAML will still be loaded and processed in each instantiation of the control. This is avoidable however, see the next section.
Refactoring 2:
Control
with resource dictionaryEven better, in terms of performance, is to refactor the
ControlTemplate
into a resource dictionary. This totally eliminates the per-control instance XAML load and (in my experience) results in almost no delay at all.Replace the original
.xaml
file with "MyControlResources.xaml
" such as the following:This resource dictionary needs to be added to a merged dictionary in
app.xaml
.Replace the original
xaml.cs
file with a plainMyControl.cs
file containing:Note that there is no longer any call to
InitializeComponent()
. The style system is used to apply the control template whose XAML is loaded only once.This is a somewhat more substantial refactoring but still relatively easy to carry out as usually few other code modifications are needed. Bindings originally made by
ElementName
to the top level control directly should be changed to useTemplateBinding
.You could organize the control template & style resources in other ways, this just shows an approach which directly corresponds to the original organization of code for the user control. Personally I like to have one resource dictionary corresponding to one control.