简体   繁体   中英

Multiple instances of the same ResourceDictionary

I have found this post about improving performance of ResourceDictionaries on the web, but the problem is that it's pretty old (2011). I was thinking about implementing something like this, but I'm wondering if Microsoft has not fixed this in the last releases of .NET Framework. I have few questions regarding this topic, which, I hope someone here can give an answer to:

  1. Is .NET Framework 4.6.1 still managing ResourceDictionaries by making multiple instances of them, one for every time they are assigned to a control?
  2. Is it even an issue when I have for example style "CustomButtonStyle" in my ResourceDictionary called "ButtonStyles" in assembly called "StylesAssembly" , which is then referenced in App.xaml of an application, that has 20 Buttons with CustomButtonStyle assigned to them?
  3. Do I understand it correctly, that in the case above, there will be 20 instances of "ButtonStyles" ResourceDictionary ?

Thanks @mm8 for posting your answer. It's 100% correct, I just want to post my own answer, because I found out something interesting, that can be useful for someone else.

The answer is: ResourceDictionary instance will be created just once if referenced in the application (no matter many controls uses its styles), BUT it will be instantiated again for every time it is referenced in another ResourceDictionary that is also used in the application.


So to give you example of this case let's say we have the following structure:

- StylesAssembly.dll
  - ButtonResourceDictionary.xaml
  - CustomButtonResourceDictionary.xaml

- Application.exe
  - App.xaml
  - MainWindow.xaml

ButtonResourceDictionary.xaml has the following code:

<Style x:Key="DefaultButtonStyle" TargetType="{x:Type Button}">
    <!-- Some setters -->
</Style>

CustomButtonResourceDictionary.xaml has the following code, which uses ButtonResourceDictionary.xaml :

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="ButtonResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style x:Key="CustomButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource DefaultButtonStyle}">
    <!-- Some setters -->
</Style>

Application.exe has a reference to StylesAssembly.dll and there is a following code in the App.xaml :

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/StylesAssembly;component/ButtonResourceDictionary.xaml" />
            <ResourceDictionary Source="pack://application:,,,/StylesAssembly;component/CustomButtonResourceDictionary.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Now if our MainWindow.xaml has something like this in it, the ButtonResourceDictionary.xaml will have only one instance :

<StackPanel>
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
</StackPanel>

but if our MainWindow.xaml has something like this in it, the CustomButtonResourceDictionary.xaml will have one instance, but the ButtonResourceDictionary.xaml will have two instances :

<StackPanel>
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource DefaultButtonStyle}" />
    <Button Style="{StaticResource CustomButtonStyle}" />
    <Button Style="{StaticResource CustomButtonStyle}" />
    <Button Style="{StaticResource CustomButtonStyle}" />
</StackPanel>

It happens because first two Buttons use style DefaultButtonStyle from ButtonResourceDictionary.xaml , but another three Buttons use style CustomButtonStyle which comes from CustomButtonResourceDictionary.xaml , which merges ButtonResourceDictionary.xaml in its code.

Do I understand it correctly, that in the case above, there will be 20 instances of "ButtonStyles" ResourceDictionary ?

No. Only one.

Is it even an issue when I have for example style "CustomButtonStyle" in my ResourceDictionary called "ButtonStyles" in assembly called "StylesAssembly", which is then referenced in App.xaml of an application, that has 20 Buttons with CustomButtonStyle assigned to them?

If you merge the ResourceDictionary into your App.xaml and create 20 Button elements across the views in your application, there will still be only one instance of the ResourceDictionary class created.

You can confirm this yourself by adding a code-behind class to the ResourceDictionary :

Is it possible to set code behind a resource dictionary in WPF for event handling?

...and put a breakpoint in the constructor.

There will also be only one instance of the Style defined in the ResourceDictionary created.

I have recently been working on an alternative solution with a friend and I wanted to share it. The goal is to be able to use ResourceDictionaries anywhere and merge them in whatever way necessary, but still have them instantiated only once and without breaking the VS designer and Blend etc.

Instructions:
1. Use merged ResourceDictionaries in xaml as you see fit.
2. Reference nuget packages Sundew.Xaml.Optimizations and Sundew.Xaml.Optimizer
3. Add a sxo-settings.json in the root of your project and enable the ResourceDictionaryCachingOptimizer
4. Build
The build will use a caching/shared ResourceDictionary, but designer will also work because they only see the normal ResourceDictionary.

For more details see: https://github.com/hugener/Sundew.Xaml.Optimizations
And a sample: https://github.com/hugener/Sundew.Xaml.Optimizer.Sample

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM