I am putting this up because it took far too long to find the answer on the web and this is probably a common problem - it is the second time i have experienced it on my app.
When a new row with a DataGridViewImageCell becomes visible, and it has no Default value set, my DataGridView throws the following Exception:
The Following Exception occurred in the DataGridView:
System.ArgumentException: Parameter is not valid. at System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData)"
In my set up I create the DataGridViewImageColumns in Visual Studio Designer and then bind these columns to DataColumns in a DataTable by setting the DataPropertyName Properties of the DataGridViewImageColumns to match DataColumns of Type: byte[].
However, it still throws this Exception when the DataGridViewImageColumn in the new Row becomes visible.
There are two workarounds that worked for me:
Handle the DataError Event of the DataGridView like this:
private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value == DBNull.Value)
{
e.Cancel = true;
}
}
That's the option I am going with for now but I'm not a fan of suppressing Exceptions and I can see the delay in the creation of the DataGridView row due to throw + Catch by the Handler.
MSDN (http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridviewimagecolumn.aspx) says that you can handle the RowsAdded event and force a null value. I tried this:
private void dataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
foreach (DataGridViewCell cell in dataGridView1.Rows[e.RowIndex].Cells)
{
if (cell.GetType() == typeof(DataGridViewImageCell))
{
cell.Value = DBNull.Value;
}
}
}
...which didn't work.
The other option involved setting the Column CellTemplate to a Type derived from DataGridViewImageColumn with a default value of null or DBNull.Value.
It's bit late for that now - I've been at this all day.
I'm probably going to go for my option 2, but can anyone tell me how to get option 3/4 to work? Is there a best approach for this?
My solution: remove the column right after it is added (detailed reason at the end). The following code removes all potential image columns, you may want to customize this if your schema is not dynamic and you know what you want to leave out:
public Form1()
{
InitializeComponent();
dataGridView1.ColumnAdded += dataGrid_ColumnAdded;
}
void dataGrid_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
{
if (e.Column.CellType == typeof(DataGridViewImageCell))
dataGridView1.Columns.Remove(e.Column);
}
so when it comes to the actual binding
DataTable table = dataTableCombo.SelectedItem as DataTable;
dataGridView1.DataSource = table;
populating the cells will happen after adding (and the removing correction) of the columns. And the exception doesn't happen this way.
Also, in your dataGridView1_RowsAdded
event handler watch out: there's not only e.RowIndex
but there's e.RowCount
too, and it can be e.RowCount > 1
! So first I tried:
void dataGrid_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
for (int i = e.RowIndex; i < e.RowIndex + e.RowCount; i++)
{
foreach (DataGridViewCell cell in dataGridView1.Rows[i].Cells)
{
if (cell.GetType() == typeof(DataGridViewImageCell))
{
cell.Value = DBNull.Value;
}
}
}
}
but I still got some exceptions. Plus if your binding is two-way, watch out because cell.Value = DBNull.Value;
causes a change in the business object! That's the reason I advise to just rather remove the column.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With