23

我一般对资源字典和合并字典有疑问,尤其是在资源查找性能方面。经过一些性能测试后,我发现 ResourceDictionary.get_MergedDictionaries 是点击次数最多的调用(在 ANTS 分析器中检查)。我们有大约 300 个资源字典 xamls,其中很多都使用合并字典来“包含”其他样式。好吧,get_MergedDictionaries 依赖于我们应用程序的一部分,其中没有发生太多事情,大约有 1000 万次点击。所以我的猜测是我们对资源字典做的完全错误。所以我试图重构一切,我想尝试摆脱所有合并的字典。

现在到实际的问题。我试图摆脱合并的字典,但失败了。我的理解是,当您使用 StaticResource 时,查找需要在当前资源之前定义资源。我做了以下简短的例子:

一个主项目和一个自定义控件库。

自定义控件库包含 2 个 xamls。

<!-- Colors.xaml -->
<ResourceDictionary [stripped namespaces] >
    <SolidColorBrush x:Key="myColor" Color="Green"/>
</ResourceDictionary>

<!-- Templates.xaml -->
<ResourceDictionary [stripped namespaces]>
    <ControlTemplate x:Key="myTemplate" TargetType="Button">
        <Rectangle Fill="{StaticResource myColor}"/>
    </ControlTemplate>
</ResourceDictionary>

现在在主项目中,MainWindow.xaml 看起来像这样

<Window x:Class="ResourceTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/ResourceTestLib;component/Themes/Colors.xaml"/>
                <ResourceDictionary Source="/ResourceTestLib;component/Themes/Template.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <Button Template="{StaticResource myTemplate}"/>
    </Grid>
</Window>

That is the desired goal. but unfortunately this crashes because the resource "myColor" cannot be found. I of course know how to fix it, add a mergeddictionary in Templates.xaml and reference Colors.xaml but i always thought, well i never really checked, that resources are looked up depending on the logical tree and the resources of the element. My understanding is; Button is created; try to lookup template .. found; try to lookup color, not found on own resources, walk up and use the windows resources.

It seems that i'm wrong. So i hope someone can shed some light on this for me. We make heavy use of WPF and despite of this we accomplished a lot with it, but because of some wrong learned behaviour in the beginning, our performance is pretty bad just because of the resource lookup. Any help would be greatly appreciated

Thanks in advance Best regards Nico

4

4 回答 4

52

Well, I don't like answering my own question, but I guess a lot of people might stumble into this and I want to give them our current solution as an option to consider.

Like I said before, we have a lot of XAMLs, around ~300 for all different kinds of things like Shared Resources (Brushes, Colors) but also many XAMLs containing different DataTemplates, Styles for controls and also for Custom Controls. In the beginning, this approach of having a lot of XAMLs was reasonable for us because we do the same with our classes and keep them small and organized. Unfortunately, WPF doesn't like that. The more ResourceDictionaries you have and the more you merge them via MergedDictionaries the worse your performance will get. The best advice I can give you is, use as few ResourceDictionary XAMLs as possible.

We bit the bullet and merged a lot of them into one giant XAML, in fact, we do this now with a pre-compiler keeping the best of both worlds. We can use as many XAMLs as we want, just following a few constraints, and merging them on a compile in a giant XAML. The performance increase we get was remarkable. In my question I wrote "11 million hits on getMergedDictionaries" ... just "precompiling" one of our assemblies, we went down to 2million hits and the performance is in the whole application at all times a lot better.

So in the end. XAML resources should not be considered as source code that gets compiled, instead, it should be understood as an actual resource that, when declared, exists, takes up space and performance.

Well, we had to learn that the hard way. I hope everyone reading this can improve their projects by learning from our mistakes.

于 2011-07-29T10:27:23.620 回答
3

I tend to go the route of using only one ResourceDictionary in an application to avoid any performance issues.

To keep the XAML manageable, I use the XAML regions Visual Studio plugin and wrap each category of resources in a region.

  • Brushes
  • Text Styles
  • etc...

For this scenario, the plugin is an absolute life saver. http://visualstudiogallery.msdn.microsoft.com/3c534623-bb05-417f-afc0-c9e26bf0e177

于 2012-01-05T17:08:23.127 回答
1

Using SharedResourceDictionary instead of ResourceDictionary completely solved MergedDictionaries performance issue for me: http://www.wpftutorial.net/MergedDictionaryPerformance.html

于 2011-08-05T11:39:40.623 回答
0

Was any light shed on the resource lookup procedure? Why was "myColor" not found?

By the way, I found a way to make it work - but a strange and unstable way. If Application.xaml has this code, the color should be found:

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/ResourceTestLib;component/Themes/Colors.xaml"/>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/ResourceTestLib;component/Themes/Template.xaml"/> 
        </ResourceDictionary.MergedDictionaries> 
    </ResourceDictionary>
</ResourceDictionary.MergedDictionaries>

If, on the other hand, you include this code into another XAML, which you then include into Application.xaml - it doesn't work, even though the resource structures are identical (verified with Snoop).

于 2012-07-12T12:37:37.097 回答