views:

61

answers:

2

I would like to bind an Image to some kind of control an delete it later on.

path = @"c:\somePath\somePic.jpg"
FileInfo fi = new FileInfo(path);
Uri uri = new Uri(fi.FullName, UriKind.Absolute);
var img = new System.Windows.Controls.Image();
img.Source = new BitmapImage(uri);

Now after this code I would like to delete the file :

fi.Delete();

But I cannot do that since the image is being used now. Between code fragment 1 en 2 what can I do to release it?

+1  A: 

copy the image to MemoryStream before giving to imagesource it should look like this

BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.DecodePixelWidth = 30;
bi.StreamSource = byteStream;
bi.EndInit();

where byteStream is copy of file in MemoryStream

also this can be useful

ArsenMkrt
Tx, it works. For later readers : I have copied it to a memorystream like this : MemoryStream byteStream = new MemoryStream(File.ReadAllBytes(path));
Peter
Yes it works, **but it is inefficient** because: 1. Two copies of the image data are kept around forever, and 2. The cache is bypassed so the image is loaded even if it is already in RAM. The linked article explains a workaround for #1 but it requires a lot of extra code and still doesn't solve #2. A much better solution is `BitmapCacheOption.OnLoad` combined with `BeginInit/EndInit`.
Ray Burns
+2  A: 

You could use a MemoryStream but that actually wastes memory because two separate copies of the bitmap data are kept in RAM: When you load the MemoryStream you make one copy, and when the bitmap is decoded another copy is made. Another problem with using MemoryStream in this way is that you bypass the cache.

The best way to do this is to read directly from the file using BitmapCacheOptions.OnLoad:

path = @"c:\somePath\somePic.jpg"

var source = new BitmapImage
{
  UriSource = new Uri(path, UriKind.RelativeOrAbsolute),
  CacheOption = BitmapCacheOption.OnLoad,
};
source.BeginInit();
source.EndInit();  // Required for full initialization to complete at this time

var img = new System.Windows.Controls.Image { Source = source };

This solution is efficient and simple too.

Note: If you actually do want to bypass the cache, for example because the image may be changing on disk, you should also set CreateOption = BitmapCreateOption.IgnoreImageCache. But even in that case this solution outperforms the MemoryStream solution because it doesn't keep two copies of the image data in RAM.

Ray Burns
Sounds really good, but I am getting a : *Cannot set the initializing state more than once.* at *source.BeginInit();*
Peter
Sorry: I hadn't tested the code using that particular constructor overload. It appears to call `BeginInit()` and `EndInit()` internally. I've changed the code to use the regular constructor, which should fix that problem.
Ray Burns
More problems : 1. I don't see Source as a property of the BitmapImage class 2. If I replace it by UriSource, I still get that it is not initialized ...It works though if I use it like this : <code> var source = new BitmapImage(); source.BeginInit(); source.UriSource = new Uri(path, UriKind.Absolute); source.CacheOption = BitmapCacheOption.OnLoad; source.EndInit();</code>+1 nevertheless for the correct idea, thx.
Peter