Resources and WinForms

This article was originally published in the "Chris Sells on .NET" newsletter

A resource is a named piece of data bound into the assembly at build time. For example, you could set the background image of a form in your application by loading a bitmap from a file, like so:

public MainForm() {
  InitializeComponent();
  this.BackgroundImage = new Bitmap(@"C:\WINDOWS\Web\Wallpaper\Azul.jpg");
}

The problem with this code, of course, is that not all installations of Windows will have Azul.jpg and even those that do may not have it in the same place. Even if you shipped this picture with your application, a space-conscious user may decide to remove it, causing your application to fault. The only safe way to make sure that the picture, or any file, stays with code is to embed it as a resource. You can do this in two ways. One way is to right-click on your project in the Solution Explorer, choose Add New Item and open the file you’d like to embed as a resource. The file will be copied into your project’s directory, but will still not be embedded. To embed a file as a resource, right-click on the file and choose Properties, changing the Build Action from Content (the default) to Embedded Resource. Once you’ve done that, you can load it at runtime. Many of the .NET classes provide constructors that take resource identifiers, like the Bitmap:

public MainForm() {
  InitializeComponent();
  this.BackgroundImage = new Bitmap(this.GetType(), "Azul.jpg");
}

When embedded as a resource, the full name will be composed of the project’s default namespace and the name of the file where the resource came from, e.g. MySecondApp.Azul.jpg. When the picture is loaded at runtime, the first argument is a type that shares the same namespace as that of the embedded resource and the string is the rest of the name.
Luckily, if the resource naming scheme is less than intuitive for you or you’d really like to see what the background image is going to look like in the designer, you can set the value of many properties in your forms by using the Property Browser directly, skipping the need to write the resource loading code at all. For example to set the background image for a form, you merely have to press the “…” button in the Property Brower next to the BackgroundImage property, choose the file from the file system and the data will be read directly into a bundle of resources maintained for that form. This causes the image to be shown in the designer and the code to be generated that loads the resource at runtime:

namespace MySecondApp {
  public class MainForm : System.Windows.Forms.Form {
  public MainForm() {
    InitializeComponent();
  }
 
  private void InitializeComponent() {
    System.Resources.ResourceManager resources =
      new System.Resources.ResourceManager(typeof(MainForm));
    ...
    this.BackgroundImage =
      (Bitmap)resources.GetObject("$this.BackgroundImage");
    ...
  }
  ...
}

In this case, instead of using the Bitmap constructor directly, the generated code is using the ResourceManager class. This class will load the bundle of resources specific to this form, whether those resources happen to be in the executing assembly or an assembly with a set of localized resources specific to the current user’s culture settings. This allows forms to be localized without changing a lick of code or even recompiling, but that will have to remain a topic for future articles…