MergedDictionaries和资源查找

时间:2011-07-14 12:44:27

标签: wpf performance resourcedictionary staticresource mergeddictionaries

我的资源字典和合并字典一般存在问题,特别是在资源查找性能方面。经过一些性能测试后,我发现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>

这是理想的目标。但不幸的是,这会崩溃,因为无法找到资源“myColor”。我当然知道如何修复它,在Templates.xaml中添加一个mergeddictionary并引用Colors.xaml,但我一直认为,我从未真正检查过,根据逻辑树和元素的资源查找资源。我的理解是;按钮已创建;尝试查找模板..发现;尝试查找颜色,找不到自己的资源,走上去使用Windows资源。

似乎我错了。 所以我希望有人可以为我阐明这一点。我们大量使用WPF,尽管如此我们已经完成了很多工作,但由于一开始就有一些错误的学习行为,我们的表现非常糟糕,因为资源查找。 任何帮助将不胜感激

提前致谢 最好的祝福 尼科

4 个答案:

答案 0 :(得分:46)

嗯,我不喜欢回答我自己的问题,但我想很多人可能会遇到这个问题,我想给他们当前的解决方案作为考虑的选择。

就像我之前说过的那样,我们有很多XAML,大约300种用于所有不同类型的东西,比如共享资源(画笔,颜色),还有许多XAML包含不同的DataTemplates,用于控件的样式以及用于自定义控件。在开始时,这种拥有大量XAML的方法对我们来说是合理的,因为我们对我们的类做了同样的事情并且保持它们的小而有条理。 不幸的是,WPF并不喜欢这样。您拥有的ResourceDictionaries越多,通过MergedDictionaries合并的越多,您的性能就会越差。 我能给你的最好的建议是,使用尽可能少的ResourceDictionary XAML

我们咬紧牙关并将其中很多内容合并为一个巨大的XAML,事实上我们现在使用预编译器来保持这两个世界的最佳状态。我们可以使用尽可能多的XAML,只需遵循一些约束,并将它们合并到一个巨大的XAML中进行编译。我们获得的性能提升非常显着。在我的问题中,我写了“1100万次点击getMergedDictionaries”...只是“预编译”我们的一个程序集,我们降到了200万次点击,性能在整个应用程序中总是好多了。

所以最后。不应将XAML资源视为已编译的源代码,而应将其理解为实际资源,当声明存在时,会占用空间和性能。

好吧,我们必须学习艰难的方法。我希望每个读这篇文章的人都可以通过从错误中吸取教训来改善他们的项目。

感谢所有意见和建议。

祝你好运 尼科

答案 1 :(得分:4)

我倾向于在应用程序中仅使用一个ResourceDictionary来避免任何性能问题。

为了保持XAML的可管理性,我使用XAML区域Visual Studio插件并包装区域中的每个类别的资源。

  • 刷子
  • 文字样式
  • 等...

对于这种情况,该插件是绝对的生命保护程序。 http://visualstudiogallery.msdn.microsoft.com/3c534623-bb05-417f-afc0-c9e26bf0e177

答案 2 :(得分:1)

使用SharedResourceDictionary而不是ResourceDictionary完全解决了MergedDictionaries性能问题: http://www.wpftutorial.net/MergedDictionaryPerformance.html

答案 3 :(得分:0)

资源查找程序是否有任何问题?为什么找不到“myColor”?

顺便说一下,我找到了一种让它起作用的方法 - 但这是一种奇怪且不稳定的方式。如果Application.xaml有此代码,则应找到颜色:

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

另一方面,如果您将此代码包含到另一个XAML中,然后将其包含到Application.xaml中 - 即使资源结构相同(使用Snoop验证),它也不起作用。