none
¿Por que el pictureBox bloquea el fichero de la imagen?¿como lo evito? RRS feed

  • Pregunta

  • Hola a todos

    Tengo un pequeño gran problema que no sé como solucionar, a ver si podéis echarme una mano

    En mi aplicación tengo varios pictureBox y les introduzco una imagen por código de una forma similar a esta

    Bitmap btmtmp=New Bitmap("ruta");

    MyPictureBox.Image=btmtmp;

    El problema es que al hacerlo de esta forma el pictureBox me bloquea el archivo y no puedo borrarlo, o sustituirlo, y no sé por qué.

    ¿Hay alguna forma para que no bloquee el fichero? es decir, que cargue la imagen en memoria, y que cierre el fichero para que pueda borrarlo (o lo que sea) desde el Explorador de Windows  sin que afecte a la aplicación (no quiero que se borre, ni que se quite, ni se actualice el PictureBox).

    Un saludo y gracias de antemano.

     

    miércoles, 14 de julio de 2010 8:55

Todas las respuestas

  • Prueba esto:

     

            Dim stream As IO.StreamReader = New IO.StreamReader("c:\1.jpg")

     

            Dim im As Image = Image.FromStream(stream.BaseStream)

            stream.Close()

            PictureBox1.Image = im


    Para el correcto funcionamiento, y que otros usuarios se puedan beneficiar de la solucion de esta pregunta por favor marca las respuestas que te hayan ayudado como "Respuesta".
    Si la respuesta te ha sido util Votala.
    Mi Blog: Jtorrecilla
    Enlace a Faq de Winforms en Ingles Muy bueno
    miércoles, 14 de julio de 2010 9:00
    Moderador
  • Hola otra vez.

    En principio si funciona, lo he cambiado en toda la aplicacion y ahora me produce un error que no sé como solucionar.

    El caso es que cuando asigno una imagen en la propiedad backgroundimage de los controles Panel y Label me sale un error al ejecutar la aplicacion indicando memoria insuficiente. Solo en release, en debug, lo hace pero en vez de cargar la imagen carga una X roja.

    es decir, todo lo hace bien si uso esta linea (salvo que bloqeua el archivo)

    lblDes.BackgroundImage = new Bitmap(@"C:\31001_2.png");
    

    Pero si lo hago de la siguiente forma, da un error de memoria insuficiente.

    StreamReader stream = new StreamReader(@"C:\31001_2.png");
    lblDes.BackgroundImage = Image.FromStream(stream.BaseStream);
    stream.Close();
    

    si en este bloque de codigo elimino la ultima linea (stream.close()), tambien funciona bien, pero claro no es plan de dejar los ficheros abiertos, y me seguiria dejando abierto los ficheros.

    a alguien se le ocurre que puede pasar?

    Un saludo y gracias

    viernes, 16 de julio de 2010 8:03
  • "NewSpiker" escribió:

    > El caso es que cuando asigno una imagen en la propiedad backgroundimage
    > de los controles Panel y Label me sale un error al ejecutar la aplicacion
    > indicando memoria insuficiente. Solo en release, en debug, lo hace pero
    > en vez de cargar la imagen carga una X roja.
    >
    > StreamReader stream = new StreamReader(@"C:\31001_2.png");
    > lblDes.BackgroundImage = Image.FromStream(stream.BaseStream);
    > stream.Close();

    Si le asignas un valor a la propiedad BackgroundImage del control Label, y después cierras la secuencia, es normal que te aparezca la excepción «Memoria insuficiente», porque dicha propiedad requiere que no se cierre la secuencia, ya que la imagen tiene que ser persistente.

    Si deseas aignarle una imagen de fondo al control Label, utiliza su propiedad Image en lugar de su propiedad BackgroundImage, ya que ésta última propiedad, y hablando del control Label, no está diseñada para utilizarse directamente desde el código, de ésta manera ya podrás asignarle la secuencia tal y como te ha comentado el compañero jtorrecilla:

       StreamReader stream = new StreamReader(@"C:\31001_2.png");
       lblDes.Image = Image.FromStream(stream.BaseStream);
       stream.Close();

    Pero en el caso del control Panel, como no dispone de la propiedad Image, no te va a quedar más remedio que asignarle un valor a su propiedad BackgroundImage, y como te he indicado anteriormente, la imagen tiene que ser persistente, lo que significa que no puedes cerrar la secuencia sin arriesgarte a obtener la excepción comentada.

    Lo mismo hay otra manera de asignarle un valor a la propiedad BackgroundImage del control Panel cerrando la secuencia, pero por ahora la ignoro.

    De todas maneras, no me queda muy claro el motivo de que quieras eliminar la imagen desde el Explorador de Windows cuando está siendo utilizada por un control cualquiera de tu aplicación. Lo mismo, si copias la imagen original a una ruta temporal, y muestras la imagen del archivo temporal en el control, digo yo que quedará desbloqueado el archivo gráfico original. Cuando ya no te haga falta el archivo temporal, lo eliminas desde tu propia aplicación, por ejemplo, al cerrar la misma.

    Un saludo

     


    Enrique Martínez [MS MVP - VB]
    domingo, 18 de julio de 2010 7:16
  • Hola.

    Gracias por la respuesta, esa diferencia entre el Image y BackgroundImage no la conocía.


    Lo de borrar la imagen cuando está cargada es por una necesidad externa, es decir, es otra aplicación la que me proporciona las fotos y que fotos, y dependiendo de estas, cuando actualizo la pantalla tendrá que cargar las que existan o la última versión.


    He utilizado un sistema que en principio me funciona, pero no tengo del todo claro que esté bien programado. La idea principal es copiar la imagen, pero no en disco, sino en memoria. El código mas o menos queda así:

    <pre lang="x-c#">private Image loadImage(String ruta)
    {
          Bitmap btmpTmp=new Bitmap(ruta);
          Image retorno=null
          MemoryStream memretorno = new MemoryStream();
    
          if (stream != null)
          {
            btmpTmp.Save(memretorno, System.Drawing.Imaging.ImageFormat.Png);
            retorno = Image.FromStream(memretorno);
          }
          return retorno;
    }
    

    De esta forma, por lo pronto puedo borrar los ficheros de las fotos, y creo cumpliría mis propósitos, pero reconozco que no tengo claro si está bien o no, porque me pierdo con la persistencia.

    Asumo que con esta función copio en memoria la foto y lo que se muestra es esta copia que tenemos en memoria, cuando borro el objeto picturebox o asigno null a la propiedad backgroudImage este objeto se borraría de  la memoria (cuando el recolector de basura considere oportuno claro)

    Hay algo que falle en mi planteamiento, no me gustaría encontrarme dentro de un mes que está funcionando de casualidad.

    Un saludo y gracias

     

    lunes, 19 de julio de 2010 7:25
  • "NewSpiker" escribió:

    > He utilizado un sistema que en principio me funciona,

    Pues será a tí, porque a mí no me funciona. Si muestro la imagen devuelta por la función «loadImage» en un control PictureBox, asignándosela a su propiedad Image, no puedo ni tan siquiera renombrar el nombre del archivo.

    Desde luego, sigo pensando que no hay que complicarse tanto la vida. Si tu intención es que se pueda eliminar el archivo gráfico, créate un archivo temporal y asunto resuelto.

    Si lo desea probar, aquí te dejo modificado tu procedimiento LoadImage, el cual se encargará de mostrar en un control PictureBox el archivo gráfico pasado al procedimiento:

          private void LoadImage(PictureBox pb, String ruta)
           {
               try
               {
                   // Referenciamos el objeto Image del control
                   //
                   Image img = pb.Image;
                  
                   // Destruyo la posible imagen existente en el control
                   //
                   if (img != null) { img.Dispose(); }
                  
                   // Archivo temporal
                   //
                   string fileName = Application.StartupPath + @"\Imagen1.png";
                  
                   // Copiamos el archivo sobrescribiendo
                   // el archivo temporal si éste existe.
                   //
                   File.Copy(ruta, fileName, true);
                  
                   // Mostramos la imagen en el control PictureBox
                   //
                   pb.Image = Image.FromFile(fileName);
              
               }
               catch (Exception)
               {
                   throw;
               }

           }

    Ahora, para mostrar una imagen en cualquier control PictureBox, simplemente ejecutarías:

               try
               {
                   LoadImage(pictureBox1, @"C:\Temp\Imagen1.jpg");

               }
               catch (Exception ex)
               {
                   MessageBox.Show(ex.Message);
               }

    Verás como ahora sí puedes eliminar, el archivo Imagen1.jpg. :-)

    Adapta el ejemplo a tus necesidades.

     

     


    Enrique Martínez [MS MVP - VB]
    martes, 20 de julio de 2010 16:16