我一般都遇到资源字典和合并的问题,特别是涉及资源查找性能时.经过一些性能测试后,我发现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>
Run Code Online (Sandbox Code Playgroud)
现在在主项目中,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>
Run Code Online (Sandbox Code Playgroud)
这是理想的目标.但不幸的是,这会崩溃,因为无法找到资源"myColor".我当然知道如何修复它,在Templates.xaml中添加一个mergeddictionary并引用Colors.xaml,但我一直认为,我从未真正检查过,根据逻辑树和元素的资源查找资源.我的理解是; 按钮已创建; 尝试查找模板..发现; 尝试查找颜色,找不到自己的资源,走上去使用Windows资源.
看来我错了.所以我希望有人可以为我阐明这一点.我们大量使用WPF,尽管如此我们已经完成了很多工作,但由于一开始就有一些错误的学习行为,我们的表现非常糟糕,因为资源查找.任何帮助将不胜感激
在此先感谢最好的问候尼科
wpf performance resourcedictionary mergeddictionaries staticresource
如果你在一些更大的wpf应用程序上工作,你可能会熟悉它.因为ResourceDictionaries总是被实例化,所以每次在XAML中找到它们时,我们最终可能会在内存中多次使用一个资源字典.所以上面提到的解决方案似乎是一个非常好的选择.事实上,对于我们目前的项目,这个技巧做了很多......内存消耗从800mb减少到44mb,这是一个非常巨大的影响.不幸的是,这个解决方案是有代价的,我想在这里展示,并希望找到一种方法来避免它,同时仍然使用SharedResourceDictionary.
我做了一个小例子,用共享资源字典可视化问题.
只需创建一个简单的WPF应用程序.添加一个资源Xaml
Shared.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="myBrush" Color="Yellow"/>
</ResourceDictionary>
Run Code Online (Sandbox Code Playgroud)
现在添加一个UserControl.代码隐藏只是默认值,所以我只显示xaml
MyUserControl.xaml
<UserControl x:Class="Leak.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:SharedResourceDictionary="clr-namespace:Articy.SharedResourceDictionary" Height="128" Width="128">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Leak;component/Shared.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Rectangle Fill="{StaticResource myBrush}"/>
</Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
后面的Window代码看起来像这样
Window1.xaml.cs
// [ ... ]
public Window1()
{
InitializeComponent();
myTabs.ItemsSource = mItems;
}
private ObservableCollection<string> mItems = new ObservableCollection<string>();
private void OnAdd(object aSender, RoutedEventArgs aE)
{
mItems.Add("Test");
}
private void OnRemove(object aSender, RoutedEventArgs aE)
{
mItems.RemoveAt(mItems.Count - 1);
}
Run Code Online (Sandbox Code Playgroud)
窗口xaml就像这样
Window1.xaml …