Windows Presentation Foundation 4.5 Cookbook
上QQ阅读APP看书,第一时间看更新

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:

  1. 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:
    How to do it...
  2. Right-click on the Solution node in Solution explorer, and select Add | New Project…:
    How to do it...
  3. Select a WPF User Control Library project and name it CH02.ClassLibraryResources:
    How to do it...
  4. 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.
  5. Delete the UserControl1.xaml file from the Solution explorer, as it's not needed.
  6. Add a new folder to the project, named Images.
  7. 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:
    How to do it...
  8. Right-click on the solution node and select Add | New Project…
  9. Select a WPF Application and name it CH02.UsingLibraryResources.
  10. Right-click on the References node in this new project in the Solution explorer, and select Add Reference…:
    How to do it...
  11. In the Add Reference dialog, click on the Projects tab and select the CH02.ClassLibraryResources project.
  12. Open MainWindow.xaml. Create a two row Grid with the following markup:
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
    </Grid>
  13. Add a Button to the Grid whose content is an Image, and a TextBlock. 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>    
  14. The image should show up in the designer preview. Running the application should also show the image correctly:
    How to do it...

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.