StaticResource and DynamicResource 与 性能测试
WPF provides two ways to access a logical resource:
• Statically with StaticResource, meaning the resource is applied only once (the first time it’s needed).
• Dynamically with DynamicResource, meaning the resource is reapplied every time it Changes.
The DynamicResource markup extension (System.Windows.DynamicResourceExtension) implements the ability to walk the logical tree just like StaticResource does, so DynamicResource can often be used wherever StaticResource is used to get the same effect. Nothing about the resource declarations themselves make them suited for one versus the other; choosing StaticResource or DynamicResource is mostly about deciding if you want consumers of the resource to see updates. In fact, you could even mix and match StaticResource and DynamicResource with the same resource key, although that would be a strange thing to do.
The difference
The main difference between StaticResource and DynamicResource is that any subsequent updates to the resource are reflected only to those elements that use DynamicResource. Such updates can be done in your own code (changing a yellow Brush to blue, for example) or they can be done by a user changing system settings.
StaticResource and DynamicResource have different performance characteristics. On the one hand, using DynamicResource requires more overhead than StaticResource because of the extra tracking. On the other hand, the use of DynamicResource can potentially improve load time. StaticResource references are always loaded when the Window or Page loads, whereas a DynamicResource reference is not loaded until it is actually used.
In addition, DynamicResource can only be used to set dependency property values, whereas StaticResource can be used just about anywhere. For example, you could use StaticResource as an element to abstract away entire controls!
Forward Reference Issue
1. StaticResource doesn’t support forward reference; any uses of the static resource must appear after it is declared in the XAML file.
E.g. 1:
<Window.Resources>
<Style x:Key="CommandButton" TargetType="{x:Type Button}">
<Setter Property="Template" Value="{StaticResource CommandButtonTemplate}" />
</Style>
<ControlTemplate x:Key="CommandButtonTemplate" TargetType="{x:Type Button}">
</Window.Resources>
This will throw exception “can’t find CommandButtonTemplate”, because CommandButtonTemplate is declared after CommandButton Style.But if changed to DynamicResource, it is ok.
E.g. 2:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="{StaticResource backgroundBrush}"Title="Window1" Height="300" Width="300">
<Window.Resources>
<SolidColorBrush x:Key=”backgroundBrush”>Yellow</SolidColorBrush>
</Window.Resources>
This is also not allowed. Use Dynamic Resource is OK.
2. In merged dictionary, the resource between different files must use DynamicResource.
like:
E.g. 3:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="generic/GenericBrushes.xaml" />
<ResourceDictionary Source="shared/CommandButtons/CommandButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
In GenericBrushes,we defined Brush, CommandButton use these brushed, must use dynamic resource, can’t use static resource.
GenericBrushes.xaml:
<LinearGradientBrush x:Key="CommandButtonBorderBrush" StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FF8192AB" Offset="0" />
<GradientStop Color="#FF6A7482" Offset=".5" />
</LinearGradientBrush>
CommandButton.xaml:
<Style x:Key="CommandButton" TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="{DynamicResource CommandButtonBorderBrush}" /> // Can’t use StaticResource here.
</Style>
If we reference to the definition file first, it is ok to use StaticResource:
E.g. 4:
in CommandButton.xaml add the code:
CommandButton.xaml:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../alternate/Brushes.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="CommandButton" TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="{StaticResource CommandButtonBorderBrush}" /> // Can use StaticResource here.
</Style>
3. In our system, the Themes are added in Application level, and do this in MainWindow and LoginWindow’s constructor,
public MainWindow(string user, Window loginWindow)
{
ThemeUtils.ApplyTheme(UserSettings.Current.DisplayTheme);
}
So we can use the resources , StaticResouce for all screens or controls after MainWindow constructed
-----------------------------------------------------------------------------------------------------------------------------------------
性能测试:
At runtime, DynamicResource requires more overhead than StaticResource because of the extra tracking. We make a demo try to make the performance comparison.
Demo specification:
When main window initialized, the main window will generate 30000 different styles for button into Application’s resource.
Click "Add Tab" button will add 30000 buttons with the different styles into one tab and add this tab into tab control. For StaticResourceTest, the 30000 styles all use static resource in this tab, for dynamicResourceTest, the 30000 styles all use dynamicResource.
Test Scenario:
Run the demo program, record the initial size of the memory, then open six tabs, record the average loading time and the total size of the memory.
Test Environment:
Intel(R) Core(TM)2 Duo CPU
E6550@ 2.33GHz, 1.96GB of RAM
Data Volume: control number = 30000
Test Result:
Static Resource |
Dynamic Resource |
|
Average Loading Time (Open six tabs) |
225ms |
308ms |
Average Memory Size of each tab |
18M |
22M |
另外一个memory leak问题:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/b97a5f83-5394-430e-9a78-9d3a957e3537/