2012-05-11 16 views
5

Ich habe ein Formular, das eine Picturebox enthält. Wenn das Formular geladen wird, wird das Standardbild geladen. Ich aktualisiere dann das Bild, wenn sich etwas in meinem Formular ändert, das das angezeigte Bild ändert. Die Erzeugung dieses Bildes funktioniert auch gut, ich kann das Bild auf der Festplatte sehen und es mit Farbe usw. öffnen. Im Allgemeinen öffne ich einen Dateistream an der Bildstelle und setze das Bild dann auf diese Stelle.winform picturebox Bild zeigt leere 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); 

Aber egal was ich tue das Bild erscheint leer auf dem Formular. Ich habe versucht, das Formular zu aktualisieren, das PictureBox-Steuerelement zu aktualisieren und seine sichtbare Eigenschaft sichtbar zu machen, nichts hilft.

Ich erstelle ein separates Formular, das nur eine Picturebox enthält und den Bildort an das Formular weitergibt und wiederhole den Prozess des Öffnens des Streams und setze das Bild dann an diesem Ort, wo es perfekt funktioniert.

Es werden keine Ausnahmen geworfen Der Debugger AFAIK ... ist so eingestellt, dass er alle Ausnahmen unterbricht.

Was könnte dieses Verhalten verursachen?

Jeder Rat wird geschätzt. Ich habe eine andere Anwendung, die Bildgenerierung in einem Hintergrundarbeiter-Thread und das funktioniert auch gut.

Vielleicht bietet mir mehr Hintergrund über das, was ich versuche zu tun, um mir auf den Grund zu gehen. Für jede Zeile in meiner Datagridview gibt es zwischen einer und drei Spalten, denen ein Bild zugeordnet ist. Ich habe all diese Bilder im Voraus erstellt. Beim Scrollen durch das Raster erhalte ich mit dem SelectionChanged-Ereignis ein Vorschaubild der ersten Bildspalte in meiner Bildbox. Es funktioniert perfekt. Ich habe auch Zellen, die beim Anklicken ein Formularfenster mit einer Vorschau der Bilder anzeigen, aus denen das Bild auf dem Hauptformular besteht. Das funktioniert auch perfekt. Ich kann Zeilen ändern und auf Zellen im Raster klicken und alles funktioniert. Im Grunde konstruiere ich ein neues Bild basierend auf dem, was der Benutzer auf anderen Steuerelementen auswählt, die an das Datagrid gebunden sind.

Das Problem tritt auf, wenn ich versuche, das Bild in der Bildbox auf dem Hauptformular zu ändern. Ich kann die Datenquelle aktualisieren und sehen, dass die Rasterwerte aktualisiert werden, aber das Bild, das ich jetzt mit Software von Drittanbietern neu generiere, die ich überprüfen kann, befindet sich auf der Festplatte und ist nach dem Update sichtbar. Sobald dies passiert, bekomme ich kein Bild mehr in der Bildbox im Formular, bis ich das Formular schließe und neu öffne, und dann sind alle aktualisierten Daten da und alles funktioniert wieder. Der Code, der bei der Auswahl aufgerufen wird, wurde geändert, um das Bild genau so zu setzen wie der Code, der das neue Bild aktualisiert. Es ist völlig synchron. Ich habe keine Ideen mehr, als mit einer ganz neuen Form von vorne anzufangen.

Nochmals vielen Dank für alle Vorschläge.

Ich fange von oben an. Der Gesamtablauf ist wie folgt:

Öffnen Sie ein Formular, das ein Datagrid enthält, das an eine SQL-Ansicht gebunden ist. Der dgv ist schreibgeschützt und es kann immer nur eine Zeile ausgewählt werden. Die Ansicht wird automatisch ausgefüllt, zusammen mit Steuerelementen, die an jede Spalte des Rasters gebunden sind. Dazu gehören Textfelder für einige, Kombinationsfelder und Kontrollkästchen für die anderen. Zu jeder Reihe gehört eine Reihe von Bildern. Wenn das Formular geladen wird, kann ich die Ansicht nach unten scrollen, und für jede Zeile wird ein neues Bild im Bildfeld des Formulars angezeigt. Alle diese Bilder wurden vorgeneriert. Wenn eine Zeile ausgewählt ist, können bis zu drei Bilder für die Zeile vorhanden sein. In diesem Fall werden Navigationsschaltflächen aktiviert, damit der Benutzer jedes Bild in der Vorschau anzeigen kann.

Ich wähle eine Zeile, ändern Sie die Steuerelemente im Formular, um einen oder mehrere Zellwerte in der ausgewählten Zeile zu ändern.Ich drücke dann eine Speichern-Schaltfläche, die die Datenbank und die entsprechenden Daten im Grid aktualisiert. Ich versuche dann, die Bilder für diese Zeile zu aktualisieren. An diesem Punkt verschwindet die Bilderbox und ich verliere die Vorschau auf dem Formular alle zusammen; Es erscheinen keine Bilder, bis ich das Formular schließe und wieder öffne und alles wieder gut ist, bis ich einen Speichervorgang durchführe.

Bei dem Versuch, dies zu lösen, finde ich, dass das Aktualisieren eines gebundenen dgv bewirkt, dass das selectedchanged-Ereignis mehrfach ausgelöst wird. Es gibt Code, um Fälle zu bearbeiten, in denen die Bindung nicht abgeschlossen ist oder in der Ansicht nichts ausgewählt ist. Es gibt auch Code im btnSave_Click-Handler, um den selektierbaren Event-Handler zu unterbrechen, bis die Aktualisierung abgeschlossen ist und die Images neu generiert werden. Obwohl die Zeile, die ich aktualisiert habe, in der Ansicht ausgewählt ist, ist die tatsächlich ausgewählte Zeile (wo der Pfeil positioniert ist und alle Steuerelemente anzeigen) die erste Zeile immer die "aktuelle" Zeile nach der Aktualisierung. Ich weiß noch nicht, wie ich das beheben soll. Hier ist der Code für die Auswahl geändert und die Schaltfläche Event-Handler speichern.

Hier ist ein Screenshot von der Form: enter image description here

Und der Code für die selection und btn_save Event-Handler:

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

       } 

      } 
     } 

Nach dem Update das Formular, um das gleiche, außer die Box Bild aussieht, ist weg und Daten aus der ersten Zeile werden in den Steuerelementen und nicht in der hervorgehobenen Zeile angezeigt.

AfterSave

Alle UpdatePreviewFiles tut, ist die Bilder mit den aktualisierten zu ersetzen. In ShowPreview wird das Bild auf picturebox.Image gesetzt. Alles funktioniert, bis ich ein Speichern/Update mache.

Wenn es noch etwas gibt, das ich anbieten kann, lassen Sie es mich wissen, das dauert viel zu lange, um zu lösen, ich weiß, dass es eine relativ einfache Erklärung gibt.

Nochmals vielen Dank.

+0

Sie sagen, dass es in einer vereinfachten Version gut funktioniert. Also müssen Sie anfangen, die Unterschiede zwischen den beiden zu betrachten. –

+0

Jeder Zweck für die Verwendung von Filestream? – coder

+1

Schließen Sie den Stream? –

Antwort

4

Try tun:

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

Statt um mit FileStream von Messing.

Außerdem müssen Sie this.picPreview.Image nicht auf null einstellen, nachdem Sie es entsorgen. Wenn Sie dispose aufrufen, werden alle Ressourcen freigegeben, unabhängig davon, ob Sie einen Zeiger darauf haben oder nicht.

Wenn Sie null auf etwas setzen oder in anderen und genaueren Worten, verlieren Sie einen Verweis (Zeiger) auf ein Objekt - der GC (Garbage Collector) wird seine Ressourcen freigeben.

Wenn Sie die Dispose-Methode verwenden, kann der GC sie freigeben, obwohl Sie immer noch einen Verweis darauf haben. (Danke Rowland Shaw), so einfach wieder auf Image.FromFile(imagePath) zu setzen wird gut funktionieren.

Der Verweis auf das vorherige Bild wird verloren gehen und der GC wird es entsorgen, wenn es sich anfühlt (wird nicht lange dauern, das verspreche ich).

Also, um es zusammenzufassen, würde ich vorschlagen, das GANZE Stück Code durch die einzelne Zeile am Anfang dieser Antwort zu ersetzen.

+0

Es wird nicht sofort die Müllsammlung verursachen - es erlaubt es nur, wenn es als nächstes aufgerufen wird (was an dem Punkt sein wird, etwas Speicher zuzuweisen, vorausgesetzt, es wird nicht manuell aufgerufen) –

+0

@RowlandShaw Danke für die Info! Behoben :) – SimpleVar

+0

Die Verwendung von Image.FromFile macht keinen Unterschied. Das Bild ist da, wenn das Formular geladen wird, ich aktualisiere es nur an Ort und Stelle. Es macht auch in der getrennten Form von innerhalb der gleichen Methode gut. Ich habe keinen Unterschied zwischen den Bildkästen gefunden. Aber danke. – Gary