我有一个包含图片框的表单。当表单加载默认图像加载正常。然后,当表单中的某些内容发生更改时,我会更新图像,从而更改正在显示的图像这个图像的生成也很好,我可以在磁盘上看到图像,并用油漆等打开它。一般来说,我在图像位置打开一个文件流,然后将图像设置到这个位置。
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 ...调试器设置为在所有异常中断。
可能导致此行为的原因是什么?
任何建议表示赞赏。我有另一个应用程序,它在backgroundworker线程中生成图像,并且工作正常。
也许提供更多关于我尝试做的事情的背景将帮助我深究这一点。对于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。这一切都有效,直到我进行保存/更新。
如果还有什么我可以提供让我知道,这需要太长时间才能解决,我知道有一个相对简单的解释。
再次感谢。
答案 0 :(得分:4)
尝试做:
this.picPreview.Image = Image.FromFile(imagePath);
而不是弄乱FileStream
。
此外,处理后您不必将this.picPreview.Image
设置为null
。
当你调用dispose时,无论你是否有指针,它都会释放所有资源。
将null设置为某些内容,或者使用其他更准确的单词,丢失对象的任何引用(指针) - 将导致GC(垃圾收集器)释放它的资源。
使用Dispose方法将允许GC释放它,即使您仍然有引用它。 (感谢Rowland Shaw),所以只需将其重新设置为Image.FromFile(imagePath)
就可以了。
对前一张图片的引用将会丢失,GC会在感觉就像处理它一样(不会很久,我保证)。
总而言之,我建议用这一答案开头的单行代替WHOLE代码。