2012-05-11 207 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