I’ve been writing a game recently using Avalon, as part of which I wanted to load and display a number of sprites and other graphical objects. There were two specific problems I wanted to resolve: what was the best way to cache the sprite images for efficient reuse, and how should I store and load the images themselves? In both cases, WinFX provided quite a neat solution that I wanted to share here.
To start with the problem of storing and loading images, the most straightforward approach would have been to simply load images from a bitmap file. Of course, then you have to deploy a series of image files with your application, which can become painful. Instead, Visual Studio allows you to embed resources directly into the application assembly, allowing you to distribute the executable code and any dependent resources as a single file. To achieve this, you simply have to add the bitmap images into your project and mark them as “Embedded Resources” within the content property (use F4 to bring up the properties window if it’s not currently active). The resources then get compiled into the application itself, which you can see if you inspect the assembly with ILDASM. How do you access the bitmap image itself? It’s a little opaque, but you use a command such as the following:
stream = this.GetType().Assembly.GetManifestResourceStream(file);
where file is the full filename that was embedded (e.g. “background.bmp”). You can now create an instance of BitmapImage based on this stream and use it for whatever you want: for example, you could create an ImageBrush and use it to paint the background of an element.
The second half of the problem reflects that the game I’m working on has an avatar moving around a grid of tiles. On each frame, many of the tiles need repainting, which involves loading the images again. Some kind of image cache is obviously the solution to ensuring that this gets handled with reasonable performance. Fortunately the BitmapImage class has a constructor parameter that allows exactly that:
public BitmapImage( Stream bitmapStream,
BitmapCacheOption cacheOption );
where BitmapCacheOption can be one of OnLoad, OnDemand or None. OnLoad is actually the default, so you get this caching goodness for free unless you explicitly unset it.
So here’s the working code snippet to grab an image from an assembly resource (corrected unreachable code based on comments below):
// using System.Windows.Media;
stream = this.GetType().Assembly.GetManifestResourceStream(“background.bmp”);
if (stream != null)
// following line throws NotSupportedException if bitmap resource
// is corrupt or wrong type
BitmapImage bitmapImage = new System.Windows.Media.BitmapImage(
ImageBrush ib = new ImageBrush(bitmapImage);
ib.TileMode = TileMode.Tile;
ib.Stretch = Stretch.None; // required for TileMode to take effect
MyWindow.Background = ib;
throw new NullReferenceException(“Stream is null – resource missing.”);
Incidentally, the embedded resources capability has no dependency on Avalon – you can do it just as well from a WinForms solution. Hope that helps someone. More tomorrow…