2012-05-11 198 views
5

我有一個包含圖片框的表單。當表單加載默認圖像加載罰款。然後,當我的表單中的某些內容發生更改而更改正在顯示的圖像時,我會更新圖像這個圖像的生成工作正常,我可以看到磁盤上的圖像,並用油漆等打開它。一般來說,我所做的是在圖像位置打開文件流,然後將圖像設置到此位置。winform picturebox圖像顯示爲空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); 

但無論我做了什麼,圖像在窗體上都顯示爲空白。我嘗試刷新窗體,刷新圖片框控件,將其可見屬性設置爲可見,沒有任何幫助。

我創建了一個單獨的窗體,其中只包含一個圖片框,並將圖像位置傳遞給窗體,並重復打開流的過程,然後將圖像設置到該位置,它完美地工作。

沒有異常正在拋出AFAIK ...調試器被設置爲中斷所有異常。

什麼可能會導致此行爲?

任何意見表示讚賞。我有另一個應用程序,在後臺工作線程中生成圖像,並且工作正常。

也許提供更多關於我想要做什麼的背景將幫助我深入到底。對於我的datagridview中的每一行,都有一列與三列之間的圖像相關聯。我提前生成了所有這些圖像。滾動網格我使用SelectionChanged事件獲取圖片框中第一個圖像列的預覽圖像。它完美的作品。我也有單元格,當點擊時顯示一個窗體窗口,並在主窗體上預覽組成圖像的圖像。這也很完美。我可以更改行並單擊網格中的單元格,一切正常。基本上,我基於用戶在綁定到數據網格的其他控件上選擇的內容構建新圖像。

當我嘗試更改主窗體上圖片框中的圖像時,出現問題。我可以更新數據源並查看網格值更新,但是現在我使用第三方軟件重新生成的映像可以在磁盤上進行驗證,並且在更新發生後可以查看,只是消失了。一旦發生這種情況,我不再在表單中的圖片框中顯示圖像,直到我關閉表單並重新打開,然後所有更新的數據都存在,並且所有內容都重新運行。選擇時調用的代碼更改爲設置圖像與更新新圖像的代碼完全相同。它是完全同步的。除了用全新的形式從頭開始,我正在用盡想法。

再次感謝您的所有建議。

我會從頭開始。整體流程如下:

打開一個窗體,其中包含綁定到SQL視圖的數據網格。 dgv是隻讀的,一次只能選擇一行。該視圖會自動填充,以及綁定到網格每列的控件。這些包括一些文本框,組合框和其他複選框。每一行都有一組與其關聯的圖像。當窗體加載時,我可以向下滾動視圖,並且對於每一行,窗體上的圖片框中都會顯示一個新圖像。所有這些圖像已經預先生成。選擇一行時,該行最多可以有三個圖像,在這種情況下,啓用導航按鈕以允許用戶預覽每個圖像。

我選擇一行,更改窗體上的控件以更改所選行中的一個或多個單元格值。然後我點擊一個保存按鈕,它將更新數據庫和網格中的相應數據。然後我嘗試更新這一行的圖像。此時圖片框消失,我在表單上一起丟失了預覽;在我關閉並重新打開表單之前,沒有任何圖像出現,並且一切都很順利,直到我進行保存。

在試圖解決這個問題時,我發現更新綁定的dgv會導致selectchanged事件被多次提升。有代碼來處理綁定未完成或未在視圖中選擇任何內容的情況。在btnSave_Click處理程序中還有一些代碼用於掛起selectchanged事件處理程序,直到更新完成並重新生成映像。儘管如此,即使在視圖中選擇了更新的行,實際選擇的行(箭頭所在的位置以及所有控件顯示的內容)的第一行始終是更新後的「當前」行。我不知道如何解決這個問題。這是更改選擇和按鈕保存事件處理程序的代碼。

這裏是形式的屏幕截圖:enter image description here

和代碼的的SelectionChanged和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); 

       } 

      } 
     } 

更新後的形式看起來是一樣的,除了圖片盒子不見了。 ,第一行的數據顯示在控件中,而不是突出顯示的行。

AfterSave

所有UpdatePreviewFiles所做的就是以更新的那些更換圖片。所有ShowPreview都會將圖像設置爲picturebox.Image。這一切工作,直到我做了保存/更新。

如果還有其他事情我可以提供,請告訴我,這需要很長時間才能解決,我知道有一個相對簡單的解釋。

再次感謝。

+0

你說它在一個簡化版本中工作正常。所以,你需要開始考慮兩者之間的差異。 –

+0

使用文件流的任何目的? – coder

+1

你正在關閉流嗎? –

回答

4

嘗試做:

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

而是與FileStream亂搞的。

此外,處置後不必將this.picPreview.Image設置爲null。 當您調用dispose時,無論您是否有指向它的指針,它都會釋放所有資源。

將null設置爲某些內容或其他更精確的單詞時,丟失對對象的任何引用(指針) - 將導致GC(垃圾收集器)釋放其資源。

即使您仍然有對它的引用,使用Dispose方法將允許GC釋放它。 (感謝羅蘭肖),所以簡單地重新設置爲Image.FromFile(imagePath)將工作得很好。

對前一張圖片的引用將會丟失,當它感覺像GC時會丟棄它(不會很長,我保證)。

所以總結一下,我會建議用這個答案的開頭部分的單行代碼替換整個代碼段。

+0

它不會直接導致垃圾收集 - 它只是允許它,當它下一次被調用(這將在分配一些內存,假設它不是手動調用的點) –

+0

@RowlandShaw感謝您的信息!修正:) – SimpleVar

+0

使用Image.FromFile沒有區別。當表單加載時,圖像就在那裏,我正在做的就是更新它。它也可以在同一個方法中以單獨的形式渲染。我還沒有發現任何圖畫盒之間的區別。但是,謝謝。 – Gary