2010-03-11 12 views
5

Me gustaría vincular una imagen a algún tipo de control y eliminarla más adelante.Eliminación de una imagen que ha sido utilizada por un control WPF

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); 

Ahora, después de este código me gustaría borrar el archivo:

fi.Delete(); 

pero no puedo hacer eso ya que la imagen se está utilizando ahora. Entre el fragmento de código 1 en 2 ¿qué puedo hacer para liberarlo?

Respuesta

3

copiar la imagen en MemoryStream antes de dar a Imagesource que debería tener este aspecto

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

donde byteStream es copia del archivo en MemoryStream

también this pueden ser útiles

+2

Tx, funciona. Para lectores posteriores: lo he copiado en un flujo de memoria como este: MemoryStream byteStream = new MemoryStream (File.ReadAllBytes (path)); – Peter

+1

Sí, funciona, ** pero es ineficiente ** porque: 1. Se guardan para siempre dos copias de los datos de imagen, y 2. La memoria caché se puentea para que la imagen se cargue incluso si ya está en la RAM. El artículo vinculado explica una solución para el # 1, pero requiere una gran cantidad de código adicional y aún no resuelve # 2. Una solución mucho mejor es 'BitmapCacheOption.OnLoad' combinada con' BeginInit/EndInit'. –

+0

¿No puedes cerrar la secuencia de memoria después del 'EndInit'? ¿Por qué necesitarías mantener ambos? – Jordan

11

Usted podría utilizar a MemoryStream pero que en realidad desperdicia memoria porque se guardan dos copias separadas de los datos del mapa de bits en la RAM: cuando carga el MemoryStream, realiza una copia y cuando el mapa de bits se decodifica, se realiza otra copia. Otro problema con el uso de MemoryStream de esta manera es que omite la caché.

La mejor manera de hacer esto es leer directamente desde el archivo usando BitmapCacheOptions.OnLoad:

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

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

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

Esta solución es eficiente y simple también.

Nota: Si realmente desea omitir la caché, por ejemplo, porque la imagen puede estar cambiando en el disco, también debe establecer CreateOption = BitmapCreateOption.IgnoreImageCache. Pero incluso en ese caso, esta solución supera a la solución MemoryStream porque no conserva dos copias de los datos de imagen en la RAM.

+0

Suena realmente bien, pero obtengo un: * No puedo establecer el estado de inicialización más de una vez. * At * source.BeginInit(); * – Peter

+0

Lo siento: no había probado el código usando esa sobrecarga de constructor en particular. Parece llamar 'BeginInit()' y 'EndInit()' internamente. Cambié el código para usar el constructor normal, que debería solucionar ese problema. –

+1

Más problemas: 1. No veo Source como una propiedad de la clase BitmapImage 2. Si lo reemplazo por UriSource, sigo obteniendo que no se inicialice ... Funciona si lo uso así : \t \t var source = new BitmapImage(); \t \t \t \t source.BeginInit(); \t \t \t \t source.UriSource = new Uri(path, UriKind.Absolute); \t \t \t \t source.CacheOption = BitmapCacheOption.OnLoad; \t \t \t \t source.EndInit(); +1 sin embargo, para la idea correcta, thx. – Peter

Cuestiones relacionadas