BitmapImage and local files
Written by Administrator   
Monday, 21 December 2009
Article Index
BitmapImage and local files
Working with static resources

When and how to use the BitmapImage class

 

Banner

BitmapImage is the class that will mostly be used when needing to load a file either from a remote source via a server or from the local file system. (For more information on its base class BitmapSource see BitmapSource: WPF Bitmaps.)   However there are some interesting differences between the two sources. In particular when you set a BitmapImage to a local file then it isn't downloaded in the background and the load is synchronous and blocking. If the file is located on a server then a it is downloaded in the background and you need to make use of the DownloadComplete and similar events.If you want to focus on how to handle the case when obtaining the image file involves a download see Loading Bitmaps: DoEvents and the closure pattern

Download or not?

The problem is that the documentation simply says that the Download events might not occur for some file types. What this means is that for any particular URI you specify the bitmap might or might not be downloaded in the background. This is a problem because how you handle the bitmap depends crucially on if it is downloaded or not. For example consider:

 BitmapImage bmi = newBitmapImage(uri);
textBox1.Text = bmi.Height.ToString();

If the bitmap given by the URI is downloaded then the contents of its Height property will be nonsense until it has finished downloading. You can code an event handler to wait for the download to complete but if the URI specifies a bitmap that isn't downloaded then the event just doesn't happen.

The correct way to do this job, if there is any doubt as to whether or not the bitmap will be downloaded or not, is to test the IsDownloading property:

Uri uri = new Uri(
"http://MySite/MyPic.png",
UriKind.Absolute);
BitmapImage bmi = newBitmapImage(uri);
if (!bmi.IsDownloading)
{
textBox1.Text= bmi.Height.ToString();
}
else
{
bmi.DownloadCompleted +=
 newEventHandler(
delegate(objectsender1, EventArgs e1)
{
textBox1.Text =
bmi.PixelHeight.ToString();
});
}

With the URI given then a download will be involved and the else part of the condition will be executed, with the result that the program waits until the download is completed before using a property.

If the URI is changed to:

 Uri uri= new Uri(Directory.
GetCurrentDirectory() + @"\test.jpg",
UriKind.Absolute);

then a download isn't necessary, even if the URI is on a file share, and the if part of the condition is executed.

Of course this is a messy way to do things and a suitable strategy is to write a function that does whatever is needed after the bitmap is ready and either call it at once or defer it until later as an event handler.

There are other oddities that you need to take into account when the bitmap is stored in a file specified by a URI. The first is that while it should be possible to load a bitmap via a relative URI this doesn't seem to work but it also doesn't throw any exceptions or errors.

Another problem is that the loading process never releases the bitmap. This means that once you set a file as the source of a bitmap you can't manipulate the file any further - it's still open even though it has been finished with. The solution seems to be to set the CacheOption to OnLoad.

 bmi.CacheOption=
BitmapCacheOption.OnLoad;

Loading without the constructor

Although the examples so far have demonstrated how to load a bitmap using the constructor, it is more usual to use the UriSource property. The key thing to remember is that the BitmapImage class is optimised for the storing of static images and once loaded the bitmap is frozen.

When you use the constructor the bitmap is automatically frozen after the constructor completes.

When you use the non-constructor way of creating a BitmapImage you have to explicitly call the BeginInit and EndInit method. Make all the changes you need to between BeginInit and EndInit because after this all changes to properties that affect the bitmap are ignored.

In many ways this is a more logical way to work because you can set everything up - event handlers, caching options and so on - and then start the bitmap loading. For example:

 BitmapImage bmi = newBitmapImage();
bmi.BeginInit();
bmi.CacheOption=
BitmapCacheOption.OnLoad;
bmi.UriSource =uri;
bmi.EndInit();
image1.Source = bmi;

If you now try to change the UriSource property then no exceptions or errors occur but the property remains unchanged.

<ASIN:1590599551>



Last Updated ( Sunday, 06 June 2010 )