c# - winform图片框图像显示空c#

标签 c# winforms image picturebox

我有一个包含图片框的表单。当表单加载默认图像加载正常。然后,当表单中的某些内容发生更改从而更改正在显示的图像时,我会更新图像。这个图像的生成也很好,我可以看到磁盘上的图像并用油漆打开它,等等。通常我所做的是在图像位置打开一个文件流,然后将图像设置到这个位置。

 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 事件获得图片框中第一个图像列的预览图像。它完美地工作。我还有一些单元格,当点击它时会显示一个表单窗口,其中包含构成主表单上的图像的图像的预览。这也很完美。我可以更改行并单击网格中的单元格,一切正常。基本上,我正在根据用户在绑定(bind)到数据网格的其他控件上选择的内容构建一个新图像。

当我尝试更改主窗体上图片框中的图像时出现问题。我可以更新数据源,并看到网格值更新,但是我现在使用第三方软件重新生成的图像,我可以验证它在磁盘上并且在更新发生后可以查看,只是消失了。一旦发生这种情况,我将不再在表单的图片框中获取图像,直到我关闭表单并重新打开,然后所有更新的数据都在那里,一切又重新开始。在选择更改以设置图像时调用的代码与用于更新新图像的代码完全相同。它是完全同步的。除了从头开始使用全新的形式之外,我已经没有其他想法了。

再次感谢所有建议。

我将从顶部开始。整体流程如下:

打开一个包含绑定(bind)到 SQL View 的数据网格的表单。 dgv 是只读的,一次只能选择一行。 View 与绑定(bind)到网格的每一列的控件一起自动填充。其中包括某些文本框、其他组合框和复选框。每行都有一组与之相关的图像。当表单加载时,我可以向下 ScrollView ,并且对于每一行,表单的图片框中都会出现一个新图像。所有这些图像都是预先生成的。 When a row is selected, there may be up to three images for the row, in which case navigation buttons are enabled to allow the user to preview each image.

我选择一行,更改表单上的控件以更改所选行中的一个或多个单元格值。然后我点击了一个保存按钮,它更新了数据库和网格中的相应数据。然后我尝试更新该行的图像。此时图片框消失了,我失去了表单上的预览;在我关闭并重新打开表单之前不会出现任何图像,并且在我保存之前一切都很好。

在尝试解决这个问题时,我发现更新绑定(bind)的 dgv 会导致多次引发 selectchanged 事件。有一些代码可以处理绑定(bind)未完成或 View 中没有选择任何内容的情况。 btnSave_Click 处理程序中还有代码用于暂停 selectionchanged 事件处理程序,直到更新完成并重新生成图像。尽管如此,即使在 View 中选择了我更新的行,实际选择的行(箭头所在的位置以及所有控件显示的内容)第一行始终是更新后的“当前”行。我还不知道如何解决这个问题。这是更改选择和按钮保存事件处理程序的代码。

这是表单的屏幕截图: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。这一切都有效,直到我进行保存/更新。

如果我还能提供任何其他信息,请告诉我,这需要很长时间才能解决,我知道有一个相对简单的解释。

再次感谢。

最佳答案

尝试做:

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

而不是搞乱 FileStream .

此外,您不必设置 this.picPreview.Imagenull处理后。
当您调用 dispose 时,无论您是否有指向它的指针,它都会释放所有资源。

将 null 设置为某物,或者用其他更准确的话来说,丢失对对象的任何引用(指针) - 将导致 GC(垃圾收集器)释放它的资源。

使用 Dispose 方法将允许 GC 释放它,即使您仍然拥有对它的引用。 (感谢 Rowland Shaw),所以只需将其重新设置为 Image.FromFile(imagePath)会工作得很好。

对先前图像的引用将丢失,GC 会在感觉合适时处理它(不会很长,我保证)。

总而言之,我建议用本答案开头的单行替换整个代码段。

关于c# - winform图片框图像显示空c#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10555990/

相关文章:

c# - XDocument.ToString() 删除 XML 编码标签

c# - 是否有可能从 .NET 用户类中删除或解决冲突?

c# - 添加行时保持 TextBox 滚动位置

Python XLWT - 插入与单元格右上角对齐的图像

c - C中的图像平滑

c# - Windows 7中的捕获删除操作(首选)

c# - 'FromSql' 操作的结果中不存在所需的列,[NotMapped] 没有帮助

c# - 从 Windows 文件资源管理器拖放到 Windows 窗体上不起作用

c# - 在 C# winform 中通过 TabIndex 获取元素的文本

javascript - 如何知道图像是否从用户的网络缓存中提取或如何获得准确的加载时间?