Saturday, September 19, 2009

Understanding WPF ResourceDictionary

When I did a WPF training to .net 2.0 audience, it took some more time to explain the concept of Resource dictionaries.The were all familiar to the resource concept in .net and were trying to relate this to the resource files.
What is ResourceDictionary in WPF

WPF resource dictionary is just a collection of objects which are accessible by their corresponding key.

The objects here means anything which are derived from System.Object.Including integers, strings and controls like TextBlock and Buttons.  Normally people thinks that ResourceDictionary is something which is related to Window, Styles & Templates.The problem is that we normally use ResourceDictionary along with Styles and Templates.See a simple sample below.

<Window x:Class="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="Window1">
    <Window.Resources>
        <sys:Byte x:Key="day">18</sys:Byte>
        <sys:String x:Key="month">Apr</sys:String>
        <sys:Int32 x:Key="year">1984</sys:Int32>
        <TextBlock x:Key="monthtxt"
                   Text="{StaticResource month}" />
        <sys:Double x:Key="fontsize">14</sys:Double>
    </Window.Resources>
    <StackPanel Orientation="Horizontal">
        <TextBlock FontSize="{StaticResource fontsize}"
                   Text="My DOB :" />
        <ContentControl  Content="{StaticResource day}" />
        <ContentControl Content="{StaticResource monthtxt}" />
        <ContentControl Content="{StaticResource year}" />
    </StackPanel >
</Window>
Note that the integer and string are from mscorlib.

Who all can have ResourceDictionary
In simple words who has a property of type ResourceDictionary can hold resources. Here the Resources property defined in one of the base classes called FrameworkElement. Most of the WPF elements are inherited from FrameworkElement and hence they can hold resources.


Accessing objects in ResourceDictionary
There are mainly 2 ways to get objects from ResourceDictionary.One is through XAML with mark-up extension and other through code.The above code shows how to retrieve through the StaticResource markup extension.Another method is through the tag <StaticResource>



<Window x:Class="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <Window.Resources>
        <sys:String x:Key="fullname">Joy George K</sys:String>
        <TextBlock x:Key="nametxt"
                   Text="{StaticResource fullname}" />
    </Window.Resources>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="FullName :" />
        <StaticResource ResourceKey="nametxt" />
    </StackPanel >
</Window>

Accessing from Code

Dim fullname As String = Me.FindResource("fullname")
If Not String.IsNullOrEmpty(fullname) Then
    MessageBox.Show("My FullName :" & fullname)
End If

My current project is in VB.Net and that is why you are seeing vb code instead of C# :-)

Merged ResourceDictionaries

Now one question comes.I have so many resources in ResourceDictionary such as Brushes, ControlTemplates and Styles.Can I categorize these in to separate files and merge them like CSS ?

Yes.It is possible by using Merged ResourceDictionaries.Add ResourceDictionary files by following the steps below and merge them at your Window or Application level.

Right click on the project -> Add -> ResourceDictionary


The below code show how to merge the ResourceDictionaries into your Window.xaml

<Window x:Class="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="brushes.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="FullName : Joy George K"
                   Background="{StaticResource background}" />
    </StackPanel >
</Window>

 Static & Dynamic ResourceDictionaries
We have seen the resources are being accessed by a mark-up extension StaticResource. Normally one question comes into our mind as a developer.Is there something called DynamicResource?
Yes.There exists DynamicResource mark-up extension too.Then what are the differences?
The main difference between Static and Dynamic resource mark-up extensions is the value calculation.In StaticResource it is done only once.But in DynamicResource it is done when ever the value of the resource changes.
I know it is difficult to understand.First question will be how to change the value of resource ? Simple .Its by code.
Lets take one example.There is a Brush resource in ResourceDictionary with color white and key backBrush.We have used this brush to give background to 2 StackPanels.One is by StaticResource and another is by DynamicResource mark-up extension.
It will work fine.When we run the application both these StackPanels will have white as background.Now suppose if I change the value of backBrush resource to Red through code what will happen? The answer is .The StackPanel which used DynamicResource will get the Red color and the other will be still in white.Hope this clears.


Refer this sample if you are still in confusion.

4 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. excelente post ... thanks

    ReplyDelete
  3. Very helpful post :) Thanks a lot ;)

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete