Using Resources for External Content - Page 1
       by kirupa  |  12 January 2007

Resources are used when dealing with external content. When you have an application with images, icons, external text files, etc., you can refer to the external content by accessing the file's path directly, for example: C:\Kirupa\title.gif. That approach works well, and your application will access the file from that location. There is a catch though!

When you decide to share your application with others, unless their computers have a title.gif in their C:\Kirupa folder, they won't be able to see the external content that you could see on your computer. Web developers are are all too familiar with this problem when they accidentally refer to a file that works on their local computer but not on the web server because they forget to upload that file to the server.

Resource files solve this problem by localizing external content to the currently running application. To look at it another way, think of your application's executable as a zip file that contains inside it other files such as your external content. When you run your application, since all of your external content is contained inside your executable, it does not matter how or where your application is run. As long as you know where your application is run, you know where your external content is.

While the example in the previous paragraph isn't representative of how an actual application works, it does give you an idea of how having external content stored in one file allows you to refer to the external content without referencing the exact location the file is stored on a user's file system.

While using resources may seem unnecessary because of the extra steps needed to access your external content, it makes it pain-free when deploying your application for other users.

Using Embedded Resources for WinForms Applications
To use resources, there are three steps you need to follow: getting the external file into your project, changing the external file's Build Action, and being using code to refer to that file. Note that the next section will discuss how to use Resources when accessing WPF-specific elements.

Importing a File
Before you can use resources, you need to first import the external file into your Project. To import a file, right click on your project icon from the Solution Explorer and go to Add | Existing Item:

[ import an item by going to Add | Existing Item ]

The Add Existing Item dialog window should appear, and you can browse for the file or files you want to import into your project. After you have imported your files, you should see it in our your Solution Explorer. For example, as shown in the following image, I inserted an image file called blue.png, and I can now see it in my Solution Explorer:

[ the imported blue.png file displayed in the Solution Explorer ]

Changing Build Action
By default, when you publish your application, your external files are kept separate from your final application. For what we are trying to do, we want our external file to be a part of the executable itself, and we can do that by changing our file's Build Action.

To change the Build Action, select your newly imported file in your Solution Explorer. Once you have selected the imported file, which in my case is blue.png, take a look at the Properties grid panel:

[ select your imported file and take a look at your Properties grid panel ]

Notice that there is an entry for Build Action. Select the Build Action entry, and  when you select it, you should see a drop-down arrow appear to the right of the Content text. Click on that arrow and select Embedded Resource:

[ change your Build Action to Embedded Resource ]

By tagging your file as an embedded resource, you tell Visual Studio to include this file as part of the assembly instead of referencing this as a separate file.

Referring to Embedded Resources using Code
With your file imported and tagged as an embedded resource, the final step is to use the embedded resource in your application. Since I've been using blue.png as an example file for the past few sections, I'll continue using that file in my example.

If I wanted to add blue.png to a WinForms button called btnSubmit, I would use the following code:

btnSubmit.Image = Image.FromStream(Assembly.GetExecutingAssembly
().GetManifestResourceStream("ButtonIcon.blue.png"));

Let's look at the above code in detail. Because I want to insert an image into my application, I use the Image class's FromStream method (Image.FromStream) which takes a stream as its argument. The reason I am looking for a method that takes a stream as an argument is because that is the main format my embedded resource will be accessible to the application.

Moving on, the Assembly class allows you to explore the various metadata associated with your program. You use the Assembly class's GetExecutingAssembly method to return an Assembly object that points to the assembly that is currently running. In other words, you are trying to find a way to explore the metadata associated with your current program!

Now that you have access to your assembly by using Assembly.GetExecutingAssembly(), the next step is to get the manifest from this assembly. More importantly, beyond just the manifest, we also want the resource the manifest provides access to. We do that using the GetManifestResourceStream() method and passing a string to the internal location of the file.

The internal location of the file follows the Namespace.filename.extension format. In my example, the namespace under which I will be accessing my blue.png resource is called ButtonIcon, and the file's name is blue, and the extension is png. Putting it all together, we get: ButtonIcon.blue.png. That's all there is to it.

Because I feel one example for something this complicated is not adequate, I have also provided the code I used to access an Embedded Resrouce text file called words.txt:

TextReader tr = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("IncrementalSearch.words.txt"));

Notice that in the above example, I am using another stream method - except on that supports text files such as StreamReader. The namespace of that particular application is called IncrementalSearch, and the name of the file I am accessing is words.txt.

Resources in WPF Applications
With the .NET Framework 3.0, you can create applications that use Windows Presentation Foundation (WPF). One of the changes introduced with .NET 3.0 is a different way of dealing with resources. Most of the steps from the previous sections still apply, and the basic idea remains the same. There are some details that are different, so let's take a look at them.

Importing External Files and Build Type
When importing external files into your WPF projects, your files' Build Type is automatically set to a new value that was not available in WinForms projects: Resource

The differences between Resource and Embedded Resource are minor, but Resource was designed with WPF in mind. As I will explain next, the way you access a Resource from an assembly is different in the WPF world.

Referring to Resources in a WPF Application
If you want to assign a resource to a WPF-specific control, you will use a  new URI-based approach for specifying how your resource will be loaded. For example, as before, let's say I have a button called btnSubmit, and I want to set it's content to the blue.png image from earlier.

The code for displaying blue.png would be:

Image imageContent = new Image();
imageContent.Source = new BitmapImage(new Uri("pack://application:,,,
/blue.png"
));
btnSubmit.Content = imageContent;

The first thing to notice is that the earlier approach of accessing the manifest from the currently active assembly is no longer used. Instead, the bizarre syntax pack://application:,,,/blue.png is used to access our resource.

The bizarre syntax is part of the Pack Uniform Resource Identifier (URI) used in the XML Paper Specification (XPS), but I won't be devoting time in this tutorial to discuss the internals of why the syntax is the way it is. The reason is, for almost all of your applications, you will simply use the same URI string with the only change being the filename/extension. You do not even have to worry about specifying your application's namespace like you did earlier.

Mixing Embedding Approaches
The above method works only with content that supports URI-based resource handling such as all WPF-specific content. Because you may run into situations where you cannot use URIs, you can always use the traditional method for embedding resources.

The following code provides an example where you use both URIs as well as as the resource path:

Image imageContent = new Image();
imageContent.Source = new BitmapImage(new Uri
("pack://application:,,,/blue.png"));
btnSubmit.Content = imageContent;
 
TextReader tr = new StreamReader(Assembly.GetExecutingAssembly()
.GetManifestResourceStream("IncrementalSearch.words.txt"));
txtMain.Content = tr.ReadLine();

When attempting to use the assembly path approach, just remember to set the Build Type for those files to Embedded Resource.


Just a final word before we wrap up. What you've seen here is freshly baked content without added preservatives, artificial intelligence, ads, and algorithm-driven doodads. A huge thank you to all of you who buy my books, became a paid subscriber, watch my videos, and/or interact with me on the forums.

Your support keeps this site going! 😇

Kirupa's signature!





SUPPORTERS:

kirupa.com's fast and reliable hosting provided by Media Temple.