Using Resources in Visual Studio .NET

by Dejan Jelovic

Visual Studio .NET seems to have a weird model for adding and managing resources such as bitmaps and locale-specific strings. It doesn't work in all the cases, it's illogical, tool support is poor, and it's badly documented.

This document is a tutorial that makes sense of this mess.

Concepts

Here's how things break down:

In Visual Studio .NET, many resources are no longer specified using .RC files. Instead, the form editor directly manipulates your VB or C# code when you edit the forms visually..

We still need other types of resources, though. We need graphic resources like bitmaps and icons, as well as locale-specific string resources. These are typically stored in one or more .RESX files that make up a Visual Studio project.

In order to use resources from your code, you'll need to know how to:

  1. Create RESX files.
  2. Add bitmaps and other types of resources to the RESX files.
  3. Load these resources from your code.

So let's get started.

1. Create RESX Files

Visual Studio .NET stores resources like bitmaps, icons and locale-specific strings in files with the extension .RESX. These are actually XML files in which binary resources are base64-encoded.

When you compile a project the compiler will compile these files into binary files with the .resource extension, and then the linker will put these into the final EXE or DLL.

Adding a new RESX file to a project is simple. Simply right-click on a project in the Solution Explorer, select Add/Add New Resource, and add a new "Assembly Resource File".

2. Adding Resources to RESX Files

Here's the funny thing: Visual Studio doesn't seem to have any tools for visually editing resources in a RESX file.

Fortunately, a Lutz Roeder has created a tool named Resourcer that you can use to edit them.

To add a bitmap to a RESX file:

  1. Run Resourcer.
  2. Open the RESX files that you have added to the Visual Studio project in Resourcer.
  3. Select Add/Add File.
  4. In the dialog that pops up, type in the file name of the bitmap file and a symbolic name by which the content of that bitmap will be known inside the RESX file.
  5. When you click OK, the content of the bitmap will be base64 encoded and placed in the RESX files under the name that you have specified.
  6. Save the RESX file by selecting File/Save.

And you are done. BTW, you don't need to keep the bitmap file on the disk any more, as the RESX file contains its complete copy.

3. Using Resources from Your Code

Here's how to load the bitmap from the resources at run time:

The first thing you should know is under which name Visual Studio has placed your RESX file into the resulting EXE.

Each Visual Studio project has a namespace name associated with it. If you right-click on a project file in Solution Explorer, then select Properties, a dialog that pops up lets you select a "Default Namespace". Visual Studio will bundle the resources into the resulting EXE under the name made up from the default namespace and the name of the RESX file.

Say your default namespace is MyCompany.MyProject and the RESX file is named SomeResources. Those resources will be bundled inside the resulting executable under the name MyCompany.MyProject.SomeResources.

To access those resources from your code, you'll need to create an instance of ResourceManager:

ResourceManager resourceManager = new ResourceManager ("MyCompany.MyProject.SomeResources", GetType ().Assembly);

Then, to obtain bitmap, you will use the symbolic name that you have specified when you have added the bitmap to the RESX file using Resourcer:

Bitmap image = (Bitmap)resourceManager.GetObject ("MyBitmapName");

If you attempt to create a resource manager using a wrong name, or you specify a wrong name when calling ResourceManager.GetObject, the framework will throw the MissingManifestResourceException.

That's it. Have fun now.


Addendum

I just got an e-mail from Ian Griffiths. He tells me that there's an easier way to store locale-neutral resources (typically icons and bitmaps) in a project. Simply add them to the project as you would any other file, and then set their Build Action to Embedded Resource.

Loading these is still weird, though. Say you want to load a bitmap. The easiest way to do that is to use the class Bitmap constructor of the form:

Bitmap (Type type, string resource);

The first parameter is the type that "owns" the resource, and the second is the name of the resource.

Now comes the weird part: The resource loader attempts to load the resource which has the name of the namespace to which type belongs, plus the passed resource name. So if you are inside a method of a class MyCompany.MyProject.MySubProject.MyClass and you attempt to load a resource named MyBitmap.bmp by executing:

Bitmap bitmap = new Bitmap (GetType (), "MyBitmap.bmp");

Then the resource loader will attempt to load the resource named  MyCompany.MyProject.MySubProject.MyBitmap.bmp.

How do you get a resource to have that name? Simply, the resource name in the manifest is formed from the project's default namespace and it's filename. So if your project's default namespace is MyCompany.MyProject, you'll need to name the bitmap file MySubProject.MyBitmap.bmp.

 

 

Read more...


Content of this site is Dejan Jelovic. All rights reserved.