Using binary resources

Binary resources are just that: chunks of bytes that typically mean something to the application, such as image or font files. In this recipe, we'll cover the basics of adding and using a binary resource.

Getting ready

Make sure Visual Studio is up and running.

How to do it...

We'll create a simple application that uses an image file added as a binary resource:

  1. Create a new WPF Application named CH02.BinaryResources.
  2. Let's add a logical images folder to the project. Right-click the project node in Solution Explorer, and select Add | New Folder.
    How to do it...
  3. The folder is created as NewFolder1. Change its name to Images.
  4. Right-click on the newly created Images folder, and select Add | Existing Item…:
    How to do it...
  5. Navigate to some image file on your system (don't forget to change the file type filter to Image files at the bottom of the open file dialog box). I've used apple.png (found in the downloadable source for this chapter), but any image will do, preferably no larger than 48 x 48 pixels. The solution explorer should look something as follows:
    How to do it...
  6. Right-click on the newly added file and select Properties:
    How to do it...
  7. In the Properties windows, make sure the Build Action is set to Resource:
    How to do it...
  8. Open MainWindow.xaml, and replace the Grid panel with a StackPanel.
  9. Add a Button control with the following markup:
    <Button Margin="10" HorizontalAlignment="Center" Padding="4">
       <StackPanel Orientation="Horizontal">
          <Image Source="Images/apple.png" />
          <TextBlock VerticalAlignment="Center" Margin="10,0,0,0"
              FontSize="16" Text="Click me, please!" />
       </StackPanel>
    </Button>    
  10. If the image you selected is large, change the Image element's Width and Height properties to something like 32 x 32 units.
  11. Notice the button shows in the designer with the selected image and text. Running the application produces the following output:
    How to do it...
  12. Add another image to the Images folder, such as Jellyfish.jpg from the {My Pictures}\Sample Pictures folder.
  13. Right-click on the newly added image and select Properties.
  14. Change the Build Action to Content.
  15. Change the Copy to Output Directory property to Copy if newer:
    How to do it...
  16. Add a property markup for the Window.Background property as follows:
        <Window.Background>
            <ImageBrush ImageSource="Images/jellyfish.jpg" />
        </Window.Background>
  17. Run the application. You should see the window background turning into a jellyfish image:
    How to do it...
  18. Close the application.
  19. Right-click on the project node in Solution Explorer and select Open Folder in Windows Explorer:
    How to do it...
  20. Navigate to the Bin\Debug\Images subfolder. Note the Jellyfish.jpg file.
  21. Delete the file.
  22. Copy the file desert.jpg from the {My Pictures}\Sample Pictures folder (or some other image to the currently open folder).
  23. Rename the file to Jellyfish.jpg:
    How to do it...
  24. Navigate back to the Debug folder and run the application directly from Windows Explorer (without doing any rebuilding).
  25. You should see the window background as the desert image instead of a jellyfish:
    How to do it...
  26. Try the same approach on the apple.png file stored in the main project folder under Images. Note that running the application from Windows Explorer (without rebuilding) does not change the image.

How it works...

The first added binary resource (the image file) is stored as a resource inside the compiled assembly. This is because the Build Action was set to Resource on the image. This makes the actual image file unnecessary when deploying the application.

These resources are part of the assembly and are stored in a resource named MyApplication.g.resources, where MyApplication is the name of the assembly. Here's a snapshot from .NET Reflector:

How it works...

Accessing the resource in XAML can be done in several ways. In the previous example, an Image was used with the Source property set to the relative URI of the image (Images/apple.png). This works because the Source property (of type ImageSource) has an appropriate type converter. This relative URI can also be used in code, as follows:

_image.Source = new BitmapImage(
  new Uri("Images/apple.png", UriKind.Relative));

When the Build Action is set to Content (as in the jellyfish example), the resource is not included in the assembly. This makes it more appropriate when the resource needs to change often (perhaps by a designer) and a rebuild would be undesirable. Also, if the resource is large, and not always needed, it's better to leave it off to the resulting assembly. Note that to access the resource, the exact same syntax is used. This is possible because WPF adds the AssemblyAssociatedContentFile attribute to the assembly, specifying the name of the resource file. Here's a view with .NET Reflector:

How it works...

That's why we were able to replace the jellyfish image with a desert image and get it to show correctly given the name jellyfish.jpg without doing any kind of rebuilding.

There's more...

The relative URI is actually a shortcut to a more elaborate (and complete) URI scheme, called pack URI. The following markup:

Source="Images/apple.png"

Is equivalent to this (more verbose) markup:

Source="pack://application:,,,/Images/apple.png"

This seems to add no value, but is actually necessary in other cases where no nice type converter exists.

The pack URI scheme is borrowed from the XML Paper Specification (XPS), and the strange three commas are not optional values with some defaults, but rather escaped slashes. The reason is that this is a URI embedded inside another URI, so some disambiguation is required. You can find more information on pack URIs in the MSDN docs at http://msdn.microsoft.com/EN-US/library/aa970069(VS.110).aspx. We'll see examples of usage of this scheme in later recipes.

Embedded Resource

The Build Action options include something called Embedded Resource. Although resources are embedded by definition, this setting cannot be used with WPF and should be avoided.