Blog Archives

WPF: Accessing Resources From An External Project

A friend asked me recently if it was possible to access resources that were created and stored in a separate assembly. Although I was sure it could be done, I’d never tried it, so I was interested in experimenting with this idea.  It turns out that the Pack URL holds the key.  Here’s an example.

Access a single ResourceDictionary

In a ResourceDictionary file named Dictionary1.xaml inside a standard WPF Application project named ‘Resources’, I have the following markup:

 

    1 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    2    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    3     <LinearGradientBrush x:Key="MyBrush">

    4         <GradientStop Color="Black" Offset="0"/>

    5         <GradientStop Color="Yellow" Offset="1"/>

    6     </LinearGradientBrush>

    7 

    8   <Style x:Key="RedButton" TargetType="{x:Type Button}">

    9     <Setter Property="Background" Value="Red"/>

   10     <Setter Property="Foreground" Value="Yellow"/>

   11     <Setter Property="Margin" Value="12,3"/>

   12     <Setter Property="Padding" Value="3"/>

   13     <Setter Property="MinWidth" Value="75"/>

   14     <Setter Property="MinHeight" Value="34"/>

   15   </Style>

   16 </ResourceDictionary>

 

Very basic resources, I know, but sufficient to demo the process. The next step is to create the ‘client’ project, the one that will use this resource.  You can either add a new project to the current solution or start a completely separate solution. In my first example, I added a WPF Application project to the solution and named it ‘ResourceUser’.

In either case, you need to add a reference to the ‘Resource’ project in the Reference section of the ResourceUser project. If you add a second project to the current solution, the project name will be available to you in the Projects tab of the Add reference dialog (as shown in the screenshot below).  If you use a separate solution, you’ll have to use the Browse tab and navigate your way to the required assembly.

 

ResDictonaries001

 

This enables you to point to the source file, i.e. the ResourceDictionary named Dictionary1.xaml in the Resource project.  The way you point to that resource is to create a ResourceDictionary in the Application.xaml file of the client project, the project that I named ResourceUser.  You set its Source property to the Dictionary1.xaml file.  As I said at the start, you use the pack URL syntax to do this. Here’s the syntax that does the job:

 

    1 <Application x:Class="Application"

    2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    4    StartupUri="Window1.xaml">

    5     <Application.Resources>

    6 

    7         <ResourceDictionary Source="pack://application:,,,/Resources;component/Dictionary1.xaml"/>

    8 

    9   </Application.Resources>

   10 </Application>

 

To avoid confusion, I probably should have named the first project something like ‘ResourceDictionarySource’, but anyway I’m sure you’ll understand that the word ‘Resources’ in that Source property refers to the name of the project.  You’ll also see that the Dictionary1.xaml file name is included as the final item.  The general syntax for the pack URL approach is:

application:,,,/<Name of project you are referencing>;component/<Name of specific file you want to access>

Once you’ve rebuilt the project, you can use the referenced resources just as you would if they existed in the client project.  To use the gradient brush and the button styles from my example above, you can do something like this in the Window of the ResourceUser project:

 

   12     <Button Style="{StaticResource RedButton}" Content="Demo" Margin="52,21,127,0" Grid.Row="1" Height="22" VerticalAlignment="Top" />

   13     <Rectangle Margin="52,28,127,17" Name="Rectangle1" Stroke="Black"

   14               Fill="{StaticResource MyBrush}"/>

Access multiple ResourceDictionaries

If the project that has the resources contains more than one ResourceDictionary, then you can use a MergedDictionaries block in the Application.xaml file of the client project. The following example assumes that the Resources project now contains two separate ResourceDictionary files named Dictionary1.xaml and Dictionary2.xaml:

 

    5     <Application.Resources>

    6 

    7     <ResourceDictionary>

    8       <ResourceDictionary.MergedDictionaries>

    9         <ResourceDictionary Source="pack://application:,,,/Resources;component/Dictionary1.xaml"/>

   10         <ResourceDictionary Source="pack://application:,,,/Resources;component/Dictionary2.xaml"/>

   11       </ResourceDictionary.MergedDictionaries>

   12     </ResourceDictionary>

   13 

   14   </Application.Resources>

 

What if you have ResourceDictionaries in the client project too?

This doesn’t present any kind of problem.  You simply add the ResourceDictionary to the MergedDictionaries collection in the usual way.  For example, if you have a ResourceDictionary named ResourceDictionary3.xaml in the ResourceUser project, you can use this syntax in Application.xaml:

 

    7     <ResourceDictionary>

    8       <ResourceDictionary.MergedDictionaries>

    9         <ResourceDictionary Source="pack://application:,,,/Resources;component/Dictionary1.xaml"/>

   10         <ResourceDictionary Source="pack://application:,,,/Resources;component/Dictionary2.xaml"/>

   11         <ResourceDictionary Source="Dictionary3.xaml" />

   12       </ResourceDictionary.MergedDictionaries>

   13     </ResourceDictionary>

 

 

What about resources that use their own resources?

So what happens if for example you have a ControlTemplate that uses images that are stored as resources in the Resource project?  Well, this isn’t a problem at all because the whole Resource project is referenced, so if the template calls for a resource file in that project when it is used in the client project, that file is available.

If that explanation isn’t as clear as you’d like, here’s an example.  In the Dictionary2.xaml ResourceDictionary, you have a Control Template for a CheckBox that uses three images.  Here’s the first part of the markup for the CheckBox Control Template:

 

    6 <ControlTemplate x:Key="ThumbCheckBox" TargetType="{x:Type CheckBox}">

    7         <Border Name="OuterBorder"

    8               BorderBrush="Black" BorderThickness="1">

    9             <Canvas Name="MainCanvas">

   10                 <Border Name="ImagesBorder" BorderBrush="DarkGray" BorderThickness="1"

   11                       Width="24" Height="32" Margin="1,1,0,0" >

   12                     <Canvas Name="ImagesCanvas">

   13                         <Image Name="ThumbDown" Source="ThumbDownSmall.jpg" Width="18" Height="26"

   14                             Canvas.Left="2" Canvas.Top="2"/>

   15                         <Image Name="ThumbUp" Source="ThumbUpSmall.jpg" Width="18" Height="26"

   16                              Margin="1"  Canvas.Left="2" Canvas.Top="2"

   17                              Visibility="Hidden"/>

   18                         <Image Name="Indeterminate" Source="QuestionMark.jpg" Width="18" Height="26"

   19                              Margin="1"  Canvas.Left="2" Canvas.Top="2"

   20                              Visibility="Hidden"/>

   21                     </Canvas>

 

You can see that there are three jpgs involved in the creation of that template.

They are all stored in the project with a Build Action of Resource.  One of the images is named ThumbDownSmall.jpg  and you can see it shown in the Solution Explorer, together with its properties in the Properties pane:

ResDictonaries002

 

If you assign this ControlTemplate to a CheckBox instance in the Window of the client project, the required images will be pulled from the Resources project as and when they are needed.  The following XAML in the client project uses the template:

 

    <CheckBox Name="chkApproval" Margin="52,14,111,36" Grid.Row="2"

         Template="{StaticResource ThumbCheckBox}"

         Content="Not Approved"

         IsChecked="{x:Null}"

         IsThreeState="True">

    </CheckBox>

 

And the result is the CheckBox you can see at the bottom of the Window:

 

ResDictonaries003

You can download the sample solution I used for this blog post.  It's available as a blog attachment or can be downloaded from here.

WP Like Button Plugin by Free WordPress Templates