5

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

 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 处理程序中还有代码可暂停 selectionchanged 事件处理程序,直到更新完成并重新生成图像。尽管如此,即使在视图中选择了我更新的行,实际选择的行(箭头所在的位置,以及所有控件显示的内容)第一行始终是更新后的“当前”行。我还不知道如何解决这个问题。这是更改选择和按钮保存事件处理程序的代码。

这是表单的屏幕截图:在此处输入图像描述

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

                }

            }
        }

更新后,除了图片框消失外,表单看起来相同,并且第一行的数据显示在控件中,而不是突出显示的行。

保存后

UpdatePreviewFiles 所做的只是用更新的图像替换图像。ShowPreview 所做的只是将图像设置为picturebox.Image。在我进行保存/更新之前,这一切都有效。

如果还有什么我可以提供的,请告诉我,这需要很长时间才能解决,我知道有一个相对简单的解释。

再次感谢。

4

1 回答 1

4

尝试做:

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

而不是乱搞FileStream.

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

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

使用 Dispose 方法将允许 GC 释放它,即使您仍然有它的引用。(感谢 Rowland Shaw),所以只需将其重新设置为Image.FromFile(imagePath)就可以了。

对前一个图像的引用将会丢失,GC 会在需要时将其处理掉(不会很长,我保证)。

所以总结一下,我建议用这个答案开头的单行替换整个代码。

于 2012-05-11T17:32:31.293 回答