- Windows Presentation Foundation 4.5 Cookbook
- Pavel Yosifovich
- 863字
- 2021-08-05 18:54:43
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:
- Create a new WPF Application named
CH02.BinaryResources
. - Let's add a logical images folder to the project. Right-click the project node in Solution Explorer, and select Add | New Folder.
- The folder is created as
NewFolder1
. Change its name toImages
. - Right-click on the newly created Images folder, and select Add | Existing Item…:
- 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: - Right-click on the newly added file and select Properties:
- In the Properties windows, make sure the Build Action is set to Resource:
- Open
MainWindow.xaml
, and replace theGrid
panel with aStackPanel
. - 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>
- If the image you selected is large, change the
Image
element'sWidth
andHeight
properties to something like 32 x 32 units. - Notice the button shows in the designer with the selected image and text. Running the application produces the following output:
- Add another image to the
Images
folder, such asJellyfish.jpg
from the{My Pictures}\Sample Pictures
folder. - Right-click on the newly added image and select Properties.
- Change the Build Action to Content.
- Change the Copy to Output Directory property to Copy if newer:
- Add a property markup for the
Window.Background
property as follows:<Window.Background> <ImageBrush ImageSource="Images/jellyfish.jpg" /> </Window.Background>
- Run the application. You should see the window background turning into a jellyfish image:
- Close the application.
- Right-click on the project node in Solution Explorer and select Open Folder in Windows Explorer:
- Navigate to the
Bin\Debug\Images
subfolder. Note theJellyfish.jpg
file. - Delete the file.
- Copy the file
desert.jpg
from the{My Pictures}\Sample Pictures
folder (or some other image to the currently open folder). - Rename the file to
Jellyfish.jpg
: - Navigate back to the
Debug
folder and run the application directly from Windows Explorer (without doing any rebuilding). - You should see the window background as the desert image instead of a jellyfish:
- Try the same approach on the
apple.png
file stored in the main project folder underImages
. 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:
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:
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.