6.3. Binary Resources
While ResourceDictionary and the resource-scope system
are fine for data that can easily be contained in an object, not all resources
fit comfortably into this model. Often it is useful to be able to deal with
binary streams. For example, images, audio, and
video have efficient binary representations, but they are not particularly at
home in markup, and in the world of objects they are usually represented by
wrappers for the underlying data. Markup itself also presents a challenge: XAML
pages must somehow get built into our applications. So, a means of dealing with
binary streams is needed.
WPF does not introduce any new technology for dealing with
binary data. The .NET framework has always provided mechanisms for dealing with
embedded binary streams, and WPF simply uses those.
The lowest level of stream support lets you embed resource
streams into any assembly. This is a simple matter of supplying the files you
would like to embed to the compiler. In Visual Studio 2005, you do this by
setting a file's Build Action property to Embedded Resource. This copies the
contents of the file into the assembly as an embedded stream. The stream can be
retrieved at runtime using the Assembly class's GetManifestResourceStream
method, as Example 6-25 shows.
Example 6-25. Retrieving assembly manifest resources
Assembly asm = Assembly.GetExecutingAssembly( );
Stream s = asm.GetManifestResourceStream("StreamName");
Streams embedded in this way are called assembly manifest
resources. Although WPF ultimately depends on this embedded-resource
mechanism, it uses it indirectly through the ResourceManager class in
the System.Resources namespace. This builds on the embedded-resource
system, adding two features: localization, and the ability to store multiple
named streams in a single low-level stream. The ResourceManager API
allows you to ask for any resource by name, and it will attempt to locate the
most appropriate resource based on the UI culture. This will be described in
more detail in the next section.
By convention, a WPF application or component puts all of its
resources into a single assembly manifest resource stream called Appname.g.resources,
where Appname is the name of the component or executable
without the file extension. This single resource stream contains binary
resources that can be extracted using a ResourceManager.
Example 6-26 shows how to retrieve a list of resource names.
Example 6-26. Listing binary resources
static List<string> GetResourceNames(Assembly asm,
System.Globalization.CultureInfo culture) {
string resourceName = asm.GetName( ).Name + ".g";
ResourceManager rm = new ResourceManager(resourceName, asm);
ResourceSet resourceSet = rm.GetResourceSet(culture, true, true);
List<string> resources = new List<string>( );
foreach (DictionaryEntry resource in resourceSet) {
resources.Add((string) resource.Key);
}
rm.ReleaseAllResources( );
return resources;
}
Let's use this code to look at the resources found inside a
typical application. Figure 6-6
shows the Visual Studio 2005 Solution Explorer view for a simple WPF project.
It contains the usual MyApp.xaml file defining the application and a
single Window1.xaml file defining the user interface. (In an
application with more windows or pages, you would see more XAML files.) This
application also has an Images directory, which contains two bitmap
files. As you can see from the Properties panel in the bottom half of
Figure 6-6, the Build Action of Sunset.jpg has been set to Resource.
When you add a bitmap file to a project using Add
New Item... or Add Existing Item...
from the context menu in the Solution Explorer, its build action will be set to Resource
automatically, so Wheel.jpg has the same setting.
If we were to call the GetresourceNames function in
Example 6-26 and print out each of the strings it returns, we would see
the following output:
myapp.baml
window1.baml
images/wheel.jpg
images/sunset.jpg
As you can see, both of the bitmaps are present. You can use
these embedded bitmaps from any element that accepts a URL for an image, as
Example 6-27 shows. A relative URL such as this one indicates to the Image
element that the resource is localrelative URLs can be used either when the
bitmap file is in the same directory, or when it is embedded as a resource.
Since the bitmap data is embedded inside the resource stream in the application
binary, there is no need to ship a separate file containing bitmap data.
Example 6-27. Using a bitmap resource
<Image Source="images/wheel.jpg" />
The resource list also shows myapp.baml and window1.baml
resources. These correspond to the two XAML files.
 |
BAML is a binary representation of an XAML file.
XAML is compiled into BAML during the compilation process for two reasons.
First, BAML is significantly more compact than XAML, so your executables are
much smaller than they would be if XAML were built in. Second, BAML is designed
to be very efficient to read, enabling the UI to load much faster than it would
if it had to parse XAML.
In a WPF project, any file with a Build Action of
Page is assumed to be XAML. It will be compiled into BAML and
embedded as a resource.
|
|
Because bitmaps, BAML files, and any other embedded binary
resource use the ResourceManager mechanism, this provides a way of
making your application localizable.
|