Accessing binary resources in code
Accessing a binary resource in XAML is pretty straightforward, but this works for standard resources such as images. Other types of resources may be used in code, and this requires a different approach.
Getting ready
Make sure Visual Studio is up and running.
How to do it...
We'll create an application that shows book information read programmatically from an XML file stored as a resource:
- Create a new WPF Application named
CH02.BinaryResourcesInCode
. - Add the
books.xml
(found in the downloadable source for this chapter) file as a resource (make sure Build Action is set to Resource). As an alternative, you can create the file yourself and type its contents as shown in the next step. - The
books.xml
file looks something like the following:<Books> <Book Name="Windows Internals" Author="Mark Russinovich" /> <Book Name="Essential COM" Author="Don Box" /> <Book Name="Programming Windows with MFC" Author="Jeff Prosise" /> </Books>
- Open
MainWindow.xaml
. Add two rows to theGrid
with aTextBox
and aButton
:<Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <Button Content="Read Book Data" FontSize="14" /> <TextBox Grid.Row="1" IsReadOnly="True" x:Name="_text" FontSize="16" Margin="4"/> </Grid>
- Add a
Click
event handler to the button. - Inside the
Click
event handler, we want to get to thebooks.xml
resource. Add the following code:var info = Application.GetResourceStream(new Uri("books.xml", UriKind.Relative));
- This returns a
StreamResourceInfo
. Now we can access theStream
property and use it in any way we want. Here's an example (you'll need to add ausing System.Xml.Linq
statement):var books = XElement.Load(info.Stream); var bookList = from book in books.Elements("Book") orderby (string)book.Attribute("Author") select new { Name = (string)book.Attribute("Name"), Author = (string)book.Attribute("Author") }; foreach(var book in bookList) _text.Text += book.ToString() + Environment.NewLine;
- Running the application and clicking the button produces the following:
How it works...
The Application.GetResourceStream
static method provides a programmatic way of accessing a resource using its relative URI (or absolute with the pack scheme). It returns a StreamResourceInfo
object, which contains two properties: ContentType
returns the MIME type (such as image/jpeg
or text/xml
) and, more importantly, the Stream
property which provides access to the actual binary data.
If the resource has been marked with a Build Action of Content, then the similar looking Application.GetContentStream
method should be used instead.
In the previous example, we've used the XElement
class (from the relatively new LINQ to XML API) to turn the binary data into a XElement
object. Then we use that object to query and display some data.
There's more...
There's actually another way to get to a resource while using core .NET types such as ResourceManager
and ResourceSet
(that have been around since .NET 1.0) instead of calling Application.GetResourceStream
. Here's one way to get the Stream
of a resource:
Stream GetResourceStream(string name) { string asmName = Assembly.GetExecutingAssembly().GetName().Name; var rm = new ResourceManager(asmName + ".g", Assembly.GetExecutingAssembly()); using(var set = rm.GetResourceSet( CultureInfo.CurrentCulture, true, true)) { return (Stream)set.GetObject(name, true); } }
This just shows that WPF has no special support for binary resources and in fact it leverages core .NET functionality in this regard.
Note that there's no counterpart for a resource on which Build Action was set to Content.