2012-05-11 27 views
5

Tengo un formulario que contiene un cuadro de imagen. Cuando el formulario se carga, la imagen predeterminada se carga bien. Luego actualizo la imagen cuando algo en mi formulario cambia y cambia la imagen que se muestra. La generación de esta imagen funciona bien también, puedo ver la imagen en el disco y abrirla con pintura, etc. En general, lo que hago es abrir una secuencia de archivos en la ubicación de la imagen y luego configurar la imagen en esta ubicación.imagen de cuadro de imagen de winform muestra vacío C#

if (this.picPreview.Image != null) 
{ 
    this.picPreview.Image.Dispose(); 
    this.picPreview.Image = null; 
} 
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); 
this.picPreview.Image = System.Drawing.Image.FromStream(fs); 

Pero no importa lo que haga, la imagen aparece en blanco en el formulario. Intenté actualizar el formulario, actualizando el control de cuadro de imagen, estableciendo su propiedad visible como visible, nada ayuda.

Creo un formulario separado que contiene solo un cuadro de imagen y paso la ubicación de la imagen al formulario y repito el proceso de apertura de la transmisión y luego estableciendo la imagen en esta ubicación funciona perfectamente.

No se están produciendo excepciones AFAIK ... depurador está configurado para romper todas las excepciones.

¿Qué podría causar este comportamiento?

Cualquier consejo es apreciado. Tengo otra aplicación que genera imágenes en un hilo de fondo y eso también funciona bien.

Tal vez proporcionar más antecedentes sobre lo que estoy tratando de hacer me ayudará a llegar al fondo de esto. Para cada fila en mi vista de cuadrícula de datos hay entre una y tres columnas que tienen una imagen asociada a ellas. He generado todas estas imágenes por adelantado. Al desplazarme por la cuadrícula obtengo una imagen de vista previa de la primera columna de imagen en mi cuadro de imagen usando el evento SelectionChanged. Funciona perfectamente También tengo celdas que cuando se hace clic en mostrar una ventana de formulario con una vista previa de las imágenes que componen la imagen en el formulario principal. Esto también funciona a la perfección. Puedo cambiar las filas y hacer clic en las celdas en la cuadrícula y todo funciona. Básicamente estoy construyendo una nueva imagen basada en lo que el usuario selecciona en otros controles que están vinculados a la cuadrícula de datos.

El problema surge cuando intento cambiar la imagen en el cuadro de imagen en el formulario principal. Puedo actualizar el origen de datos y ver la actualización de los valores de la cuadrícula, pero la imagen, que ahora regenero usando un software de terceros, que puedo verificar está en el disco y se puede ver después de que la actualización se lleva a cabo, simplemente desaparece. Una vez que esto sucede, ya no obtengo una imagen en el cuadro de imagen en el formulario hasta que cierro el formulario y lo vuelvo a abrir, y luego todos los datos actualizados están allí y todo vuelve a funcionar. El código que recibe una llamada en la selección cambió para establecer que la imagen sea exactamente igual al código en el lugar para actualizar la nueva imagen. Es completamente sincrónico. Me estoy quedando sin ideas que no sea comenzar de cero con una forma completamente nueva.

Gracias de nuevo por todas las sugerencias.

Comenzaré desde la parte superior. El flujo general es el siguiente:

Abra un formulario que contiene una cuadrícula de datos que está vinculada a una vista de SQL. El dgv es de solo lectura y solo se puede seleccionar una fila a la vez. La vista se completa automáticamente, junto con los controles que están vinculados a cada columna de la cuadrícula. Estos incluyen cuadros de texto para algunos, cuadros combinados y casillas de verificación para los demás. Cada fila tiene un conjunto de imágenes asociadas. Cuando se carga el formulario, puedo desplazarme hacia abajo por la vista y para cada fila aparece una nueva imagen en el cuadro de imagen del formulario. Todas estas imágenes han sido pregeneradas. Cuando se selecciona una fila, puede haber hasta tres imágenes para la fila, en cuyo caso los botones de navegación están habilitados para permitir al usuario obtener una vista previa de cada imagen.

Seleccionar una fila, cambiar los controles en el formulario para cambiar uno o más valores de celda en la fila seleccionada.Luego presiono un botón para guardar, que actualiza la base de datos y los datos correspondientes en la grilla. Luego intento actualizar la (s) imagen (es) para esta fila. En este punto, el cuadro de imagen desaparece y pierdo las vistas previas en el formulario todos juntos; no aparecen imágenes hasta que cierro y vuelvo a abrir el formulario, y todo vuelve a estar bien hasta que guardo.

Al tratar de resolver esto, me parece que la actualización de un dgv encuadernado provoca que el evento seleccionado sea levantado varias veces. Hay un código para manejar casos donde el enlace no está completo, o no hay nada seleccionado en la vista. También hay un código en el controlador btnSave_Click para suspender el controlador de eventos de selección de cambios hasta que se complete la actualización y se regeneren las imágenes. A pesar de hacer esto, aunque la fila que actualicé se seleccionó en la vista, la fila realmente seleccionada (donde se coloca la flecha y lo que muestran todos los controles) la primera fila es siempre la fila "actual" después de la actualización. No sé cómo arreglar eso todavía. Aquí está el código para la selección modificada y el botón para guardar los manejadores de eventos.

Aquí está una captura de pantalla de la forma: enter image description here

Y el código de los controladores de eventos SelectionChanged y btn_save:

/// <summary> 
     /// update the preview on a row selection change 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     private void dataGridView1_SelectionChanged(object sender, EventArgs e) 
     { 
      if (!BindingComplete) return; 

      DataGridView dgv = (DataGridView)sender; 

      if (!dgv.Focused || dgv.CurrentRow == null) return;   

      // set the pic preview to the current row image(s) 
      // we need the record for the current index 
      DataRowView currentDataRowView = (DataRowView)dgv.CurrentRow.DataBoundItem; 

      if (currentDataRowView == null) return; 

      DataRow currentRow = currentDataRowView.Row; 

      LastSelectedIndex = dgv.SelectedRows[0].Index; 

      Debug.WriteLine("Current row in SelectionChanged: " + currentRow.ItemArray[0].ToString()); 

      bool showBox = false, showProd = false, showWire = false; 
      string box, prod, wire; 

      string pdcProductName = currentRow.ItemArray[0].ToString(); 

      showWire = !string.IsNullOrEmpty(wire = currentRow.ItemArray[7].ToString()); 

      showBox = !string.IsNullOrEmpty(box = currentRow.ItemArray[8].ToString()); 

      showProd = !string.IsNullOrEmpty(prod = currentRow.ItemArray[9].ToString()); 

      // check for wirepath, box, and product. Enable the nav buttons if there is more than 
      // one label for this product. We need to check for LabelFileName being the same for both 
      // box and product, in which case there is one file for both which defaults to box 
      if ((showBox && showProd && prod == box) || showBox) 
      { 
       string targetFile = PreviewImagePath + pdcProductName + "_eBox.png"; 

       if (picPreview.Image != null) 
       { 
        //picPreview.Image.Dispose(); 
        //picPreview.Image = null; 
       } 

       // if the preview image doesn't exist yet use a default image 
       if (!File.Exists(targetFile)) 
       { 
        // make the loading gif invisible 
        this.picLoading.Visible = true; 

        //picPreview.Image = AdminTILE.Properties.Resources.StandardPaper; 
       } 
       else 
       { 
        this.picLoading.Visible = false; 
        Debug.WriteLine("Opening file " + targetFile); 

        FileStream fs = new FileStream(targetFile, FileMode.Open, FileAccess.Read); 
        picPreview.Image = System.Drawing.Image.FromStream(fs); 
        Image imgCopy = (Image)picPreview.Image.Clone(); 
        this.picPreview.Visible = true; 
        fs.Close(); 

        // preview in another frame 
        if (frm.IsDisposed) 
        { 
         frm = new PreviewImage(); 
        } 
        frm.PreviewLabel(imgCopy); 
        frm.Show();     

        //picPreview.ImageLocation = targetFile; 
       } 
      }    
      else if (showProd) 
      { 
       string targetFile = PreviewImagePath + pdcProductName + "_eBox.png"; 

       if (picPreview.Image != null) 
       { 
        picPreview.Image.Dispose(); 
        //picPreview.Image = null; 
       } 

       if (!File.Exists(targetFile)) 
       { 
        // make the loading gif invisible 
        this.picLoading.Visible = true; 
        //picPreview.Image = AdminTILE.Properties.Resources.StandardPaper; 
       } 
       else 
       { 
        this.picLoading.Visible = false; 
        FileStream fs = new FileStream(targetFile, FileMode.Open, FileAccess.Read); 
        picPreview.Image = System.Drawing.Image.FromStream(fs); 
        fs.Close(); 
       } 
      }   

     } 


     /// <summary> 
     /// update the database with the current selections 
     /// </summary> 
     /// <param name="sender"></param> 
     /// <param name="e"></param> 
     private void btnSave_Click(object sender, EventArgs e) 
     { 

      if (dataGridView1.SelectedRows.Count == 0) 
      { 
       MessageBox.Show("No record is selected to update"); 
       return; 
      } 

      DialogResult result1 = MessageBox.Show("Saving Label Configuration. Are you sure?", 
       "IMPORTANT!", MessageBoxButtons.YesNoCancel); 

      // update the view 
      if (result1 == DialogResult.Yes) 
      { 

       // we need the record for the current index 
       DataRowView currentDataRowView = (DataRowView)dataGridView1.CurrentRow.DataBoundItem; 
       DataRow currentRow = currentDataRowView.Row;     
       string pdcProductName = currentRow.ItemArray[0].ToString(); 



       Int32 currentIndex = dataGridView1.SelectedRows[0].Index; 

       Debug.WriteLine("Current index in Save:" + currentIndex.ToString()); 

       string AgencyId="", LogoId="", WireId=""; 

       SqlDataAdapter LabeledProductsDataTableAdapter = 
       new SqlDataAdapter("SELECT * FROM LabeledProducts", 
        printConfigTableAdapter.Connection); 

       SqlDataAdapter LogosDataTableAdapter = 
       new SqlDataAdapter("SELECT * FROM Logos", 
        printConfigTableAdapter.Connection); 

       if (vwTILEAdminTableAdapter.Connection.State != ConnectionState.Open) 
       { 
        printConfigTableAdapter.Connection.Open(); 
       } 

       DataTable LogoDataTable = new DataTable(); 
       LogosDataTableAdapter.Fill(LogoDataTable); 

       DataTable LabeledProductsDataTable = new DataTable(); 
       LabeledProductsDataTableAdapter.Fill(LabeledProductsDataTable); 

       StringBuilder sql = new StringBuilder(); 

       // Fill a table with the results of the 
       // data adapter and query the table instead of the database. 
       // An empty LogoDescription maps to an empty filename 
       DataRow dataRow; 

       if (cbAgency.SelectedItem != null) 
       { 
        sql.Append("LogoDescription = '").Append(cbAgency.SelectedItem).Append("'");      
        dataRow = LogoDataTable.Select(sql.ToString())[0]; 
        AgencyId = dataRow.ItemArray[0].ToString(); 

        sql.Clear(); 
       } 

       if (cbPrivateLabel.SelectedItem != null) 
       { 
        sql.Append("LogoDescription = '").Append(cbPrivateLabel.SelectedItem).Append("'"); 
        dataRow = LogoDataTable.Select(sql.ToString())[0]; 
        LogoId = dataRow.ItemArray[0].ToString(); 

        sql.Clear(); 
       } 

       if (cbWire.SelectedItem != null) 
       { 

        sql.Append("LogoDescription = '").Append(cbWire.SelectedItem).Append("'"); 
        dataRow = LogoDataTable.Select(sql.ToString())[0]; 
        WireId = dataRow.ItemArray[0].ToString(); 

        sql.Clear(); 
       } 


       // PdcProductName is the primary key 
       sql.Append(@"UPDATE [dbo].[LabeledProducts] 
        SET [PdcProductName] = @pdcProd 
         ,[LabelProductName] = @lblProd 
         ,[LabelDescription] = @lblDesc 
         ,[Power] = @pwr 
         ,[Fabrication] = 0 
         ,[UL_File_Number] = @ul 
         ,[PrePrintedSerial] = @pps 
         ,[ShowOrderOnLabel] = 0 
         ,[PrivateLabelLogoId] = @plid 
         ,[AgencyImageId] = @aid 
         ,[WireDiagConfigId] = @wid 
         ,[ReleasedForProduction] = @rfp 
        WHERE PdcProductName = '").Append(pdcProductName).Append("'"); 

       using (SqlCommand command = new SqlCommand(sql.ToString(), vwTILEAdminTableAdapter.Connection)) 
       { 
        if (vwTILEAdminTableAdapter.Connection.State != ConnectionState.Open) 
         vwTILEAdminTableAdapter.Connection.Open(); 

        LabeledProductsDataTableAdapter.UpdateCommand = command; 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@pdcProd", txtPdcProdName.Text); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@lblProd", txtLabeledProd.Text); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@lblDesc", txtLabelDesc.Text); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@pwr", txtPower.Text);      
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@ul", txtULFileNumber.Text); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@pps", cbPrePrintedSerial.Checked); 

        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@plid", LogoId); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@aid", AgencyId); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@wid", WireId); 
        LabeledProductsDataTableAdapter.UpdateCommand.Parameters.AddWithValue("@rfp", cbReleased.Checked); 

        //int rowsAffected = LabeledProductsDataTableAdapter.Update(LabeledProductsDataTable); 
        int rowsAffected = command.ExecuteNonQuery(); 

        // The DataViewManager returned by the DefaultViewManager 
        // property allows you to create custom settings for each 
        // DataTable in the DataSet. 
        DataViewManager dsView = this.tILEDataSet.DefaultViewManager; 

        // remove the selectionChanged event handler during updates 
        // every update causes this handler to fire three times!!! 
        this.dataGridView1.SelectionChanged -= new System.EventHandler(this.dataGridView1_SelectionChanged); 


        dataGridView1.DataSource = typeof(TILEDataSet.vwTILEAdminDataTable); 
        this.vwTILEAdminBindingSource.DataSource = typeof(TILEDataSet.vwTILEAdminDataTable); 
        this.vwTILEAdminBindingSource.DataSource = this.tILEDataSet.vwTILEAdmin; 
        this.dataGridView1.DataSource = this.vwTILEAdminBindingSource;      
        vwTILEAdminBindingSource.ResetBindings(false); // false for data change, true for schema change 

        this.vwTILEAdminTableAdapter.Fill(this.tILEDataSet.vwTILEAdmin); 

        // we need to reget the row after the update to pass to preview 
        currentIndex = LastSelectedIndex; 
        DataGridViewRow drv = this.dataGridView1.Rows[currentIndex]; 
        currentRow = ((DataRowView)(drv.DataBoundItem)).Row; 

        // update the preview files 

        UpdatePreviewFiles(currentRow); 


        // try this 
        dataGridView1.ClearSelection(); 
        // this doesn't work 
        dataGridView1.Rows[currentIndex].Selected = true; 


        // reset the selection changed handler once the update is complete 
        this.dataGridView1.SelectionChanged += new System.EventHandler(this.dataGridView1_SelectionChanged); 

       } 

      } 
     } 

Después de la actualización de la forma tiene el mismo aspecto, excepto el cuadro de imagen se ha ido , y los datos de la primera fila aparecen en los controles en lugar de la fila que se resalta.

AfterSave

Todos UpdatePreviewFiles hace es sustituir las imágenes con los actualizados. Todo lo que ShowPreview hace es establecer la imagen en el cuadro de imagen. Imagen. Todo funciona hasta que guarde/actualice.

Si hay algo más que pueda proporcionar, avíseme, esto lleva demasiado tiempo resolverlo, sé que hay una explicación relativamente simple.

Gracias de nuevo.

+0

Dice que funciona bien en una versión simplificada. Entonces, necesitas comenzar a mirar las diferencias entre los dos. –

+0

¿Algún propósito para usar filestream? – coder

+1

¿Estás cerrando la transmisión? –

Respuesta

4

trate de hacer:

this.picPreview.Image = Image.FromFile(imagePath); 

En lugar de jugar un poco con FileStream.

Además, no es necesario configurar this.picPreview.Image en null después de tirarlo. Cuando llama a disponer, libera todos los recursos independientemente de si tiene un puntero o no.

Configurando nulo en algo, o en otras palabras más precisas, perder cualquier referencia (puntero) a un objeto - hará que el GC (recolector de basura) libere sus recursos.

El uso del método Dispose permitirá que el GC lo libere aunque todavía tenga una referencia al mismo. (Gracias Rowland Shaw), por lo que simplemente volver a establecerlo en Image.FromFile(imagePath) funcionará bien.

Se perderá la referencia a la imagen anterior y el GC la eliminará cuando lo desee (no será larga, lo prometo).

Para resumir, sugiero reemplazar la pieza entera de código con una sola línea al principio de esta respuesta.

+0

No causará la recolección de basura de inmediato, solo lo permite, cuando vuelva a llamarse (que estará en el punto de asignar algo de memoria, suponiendo que no se llame manualmente) –

+0

@RowlandShaw ¡Gracias por la información! Corregido :) – SimpleVar

+0

Usar Image.FromFile no hace la diferencia. La imagen está allí cuando se carga el formulario, todo lo que hago es actualizarlo en su lugar. También representa bien en forma separada desde dentro del mismo método. No he encontrado ninguna diferencia entre las cajas de fotos. Pero gracias. – Gary

Cuestiones relacionadas