Accessing binary resources from another assembly
Sometimes binary resources are defined in one assembly (typically a class library), but are needed in another assembly (another class library or an executable). WPF provides a uniform and consistent way of accessing these resources using the pack URI scheme. Let's see how to do this.
Getting ready
Make sure Visual Studio is up and running.
How to do it...
We'll create two assemblies—one that holds resources, and another that needs to use those resources:
- Create a new blank solution by selecting File | New Project from the main menu and then navigating to Other Project Types | Visual Studio Solutions. Name it
BinaryResourceAccess
: - Right-click on the Solution node in Solution explorer, and select Add | New Project…:
- Select a WPF User Control Library project and name it
CH02.ClassLibraryResources
: - We're not going to actually use any user controls, but this is a simple way to create a class library with WPF references already included.
- Delete the
UserControl1.xaml
file from the Solution explorer, as it's not needed. - Add a new folder to the project, named
Images
. - Add some image to the resulting folder, such as
apple.png
used in the recipe Using logical resources. Make sure its Build Action is set to Resource. The solution should look something like the following: - Right-click on the solution node and select Add | New Project…
- Select a WPF Application and name it
CH02.UsingLibraryResources
. - Right-click on the References node in this new project in the Solution explorer, and select Add Reference…:
- In the Add Reference dialog, click on the Projects tab and select the
CH02.ClassLibraryResources
project. - Open
MainWindow.xaml
. Create a two rowGrid
with the following markup:<Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> </Grid>
- Add a
Button
to theGrid
whose content is anImage
, and aTextBlock
. The image should point to the image file added to the class library project:<Button HorizontalAlignment="Center" Margin="4" Padding="6"> <StackPanel Orientation="Horizontal"> <Image Source="/CH02.ClassLibraryResources;component/Images/apple.png" /> <TextBlock VerticalAlignment="Center" FontSize="14" Text="Click me!" Margin="10,0,0,0" /> </StackPanel> </Button>
- The image should show up in the designer preview. Running the application should also show the image correctly:
How it works...
WPF recognizes a pack URI to a referenced assembly in the form:
/AssemblyReference;component/ResourceName
Here, AssemblyReference
may be a simple name (as in our example), but may also include a version (with a "v" prefix) and/or the public key token (if the assembly is strongly named). Here's an example:
/MyAssembly;v2.0;4ac42a7f7bd64f34;component/images/apple.png
This is a shorthand for a full pack URI (prefixed by pack://application:,,,
), and can also be an argument to Application.GetResourceStream
, as demonstrated in the recipe Accessing binary resources in code.
There's more...
This scheme does not work with resources marked with a Build Action of Content. A way around this is to use the full pack URI with a siteOfOrigin
base. In the previous example turning the image into a Content requires modifying the Source
property of Image
to read as follows:
Source="pack://siteOfOrigin:,,,/images/apple.png"
Note that the Visual Studio designer fails to display the image and a squiggly will run under this line in the XAML editor, but it will work at runtime.