Search code examples
c#wpfnested-resources

Sharing Application Resources in WPF


From this page, I read:

If your application uses custom controls and defines resources in a ResourceDictionary (or XAML Resources node), it is recommended that you either define the resources at the Application or Window object level, or define them in the default theme for the custom controls. Defining resources in a custom control's ResourceDictionary imposes a performance impact for every instance of that control.

Ok... now, I have a UserControl that defines the following resources:

<UserControl ...>
    <UserControl.Resources>
        <Namespace:ImagesConverter x:Key="ImagesConverter" ...
        <Storyboard x:Key="AnimationHide" ...
    </UserControl.Resources>

So, because of the fact I'm creating not less than 100 instances of them at runtime, as the MSDN tutorial says, it would be better to move those resources ad MainWindow or App level. Where's the best location to move them to? MainWindow level, App level or resource file? And why?

And then... how can I use them from their new location? Let's say I have this code inside my UserControl:

m_AnimationHide = (Storyboard)Resources["AnimationHide"];

How should I modify it to reflect those changes? And how should I modify the following UserControl XAML snippet instead?

Source="{Binding Source={x:Static Properties:Resources.MyImage}, Converter={StaticResource ImagesConverter}}"

Solution

  • Personally, I prefer to use App.xaml or seperate ResourceDictionary over adding them all to the Window.Resources, this eliminates clutter in your Window xaml.

    This also allows you to easily create Themes for you application as you have them all in one place, so you can copy your existing ResourceDictionary change brush colors etc, the you can choose what ResourceDictionary you want to load and and easily change the entire apperance of your application.

    As for accessing the Resouces in your Usercontrol there is no difference on the xaml side, you will continue to use {StaticResource resourceKey} as when you call a StaticResource it searches though the Resource hierarchy to find the Resource.

    So if you move you resource from UserControl.Resources to Window.Resources or Application.Resources you don't need to change anything in your xaml code that is accessing though {StaticResource resourceKey}.

    As for access in code behind you will use FindResource("resourceKey") instead of Resources["resourceKey"] as FindResource will search the hierarchy for the Resource like the StaticResource does in xaml.

    Example:

    m_AnimationHide = (Storyboard)FindResource("AnimationHide");
    

    If you want to modify any of these Resources in a specific control and they are frozen you can just create a copy for that instance

    Example

    var animation = FindResource("AnimationHide") as Storyboard;
    
    m_AnimationHide = animation.Clone();
    m_AnimationHide.Completed += m_AnimationHide_Completed;
    

    You can also set x:Shared="false" this will return a new instance of the animation each time from the Resources, this will save copy/pasting the same animation througout your application if you have a complex Resource that you need to change values in.

    <Storyboard x:Key="AnimationHide" x:Shared="false" />
    

    Then you will be able to modify the resource locally.