"Invalid Cast Exception was Unhandled" when accessing the DataBoundItem of a C# DataGridView Row

When I click on a DataGridRow in my C# program it accesses the code, see below, which throws the following error:

"Invalid Cast Exception was Unhandled"
"Unable to cast object of type 'System.Data.DataRowView' to type 'TypedDataTableRow'."

I am puzzled by this error because the databound item is a "TypedDataTableRow". I appreciate the help of anyone who can get me past this error.

private void MyDataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
            TypedDataTable.TypedDataTableRow row = (TypedDataTable.TypedDataTableRow) MyDataGridView.Rows[e.RowIndex].DataBoundItem;

Open in new window

Who is Participating?

Improve company productivity with a Business Account.Sign Up

mattjankowskiConnect With a Mentor Author Commented:
Abel and anarki:

I have a solution, but also a dilemma.

Here is the solution:
DataRowView dvrow = (DataRowView)MyDataGridView.Rows[e.RowIndex].DataBoundItem;
TypedDataTableRow typedRow = (TypedDataTableRow)dvrow.Row;

My approach: I took what I learned from our conversation and poked around the Visual Studio debugger. I followed the data and realized there were really a series of rows that I needed to cast. I may have been able to do this in one step, but I am quite happy to have it done at all.  

My dilemma. I believe that you both helped me come to this solution. Is it possible for me to award points to you both?

Thanks again for your help!

anarki_jimbelConnect With a Mentor Commented:
try put brackets

TypedDataTable.TypedDataTableRow row = (TypedDataTable.TypedDataTableRow) (MyDataGridView.Rows[e.RowIndex].DataBoundItem);

Or might be :

TypedDataTable.TypedDataTableRow row = (TypedDataTable.TypedDataTableRow) (MyDataGridView.Rows[e.RowIndex]);

From what I get about the the TypedDataTable is that it is merely a wrapper and under the hood simply holds a reference to a DataTable. When you bind the TypeDataTable to the DataGridView, you actually bind the DataTable. The DataTable will (MVC principle) bind in fact the DataView. Each row that is displayed is than essentially the DataRowView.

This DataRowView is castable to the original data type, in this case, the DataRow. Going from the DataRow back to a TypeDataTableRow should be something like a cast (but that didn't work) or a "new TypedDataTableRow". Since Microsoft has literally zero documentation on this object (they have on TypedDataTable, though, which is why I came up with my little "under the hood wrap-up") and since I cannot test it in the absence of BizTalk (is it part of some redistributable package? then I could play with it a little) I have to guess on this part.

Is it really necessary to have the original type back? It might not be there for the reasons I laid out in the first lines above...

-- Abel --
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

abelConnect With a Mentor Commented:
hmm, on second thought, the second suggestion of anarki_jimbel (though without the second pair of parenthesis as the dot is higher in priority rank than the cast anyway) might be a good suggestion too ;-)
mattjankowskiAuthor Commented:
anarki and Abel,

Thank you for your comments. I really appreciate you both taking the time to try to help me out:

Starting with anarki's suggestions:

I tried:
TypedDataTable.TypedDataTableRow row = (TypedDataTable.TypedDataTableRow)(MyDataGridView.Rows[e.RowIndex]);
And received this error at compile:
Error 5      Cannot convert type 'System.Windows.Forms.DataGridViewRow' to 'TypedDataTable.TypedDataTableRow'.

I also tried:
TypedDataTable.TypedDataTableRow row = (TypedDataTable.TypedDataTableRow) (MyDataGridView.Rows[e.RowIndex].DataBoundItem);

And received this error:
//Unable to cast object of type 'System.Data.DataRowView' to type 'EventLoggingRow'.

And, combining Abel's Comments with anarki's suggestions:
Attempt 3:
DataRow drow = (DataRow) MyDataGridView.Rows[e.RowIndex].DataBoundItem;
//Unable to cast object of type 'System.Data.DataRowView' to type 'System.Data.DataRow'.

Attempt 4:
DataRow drow = (DataRow) scribeDGV.Rows[e.RowIndex];
//Error     5       Cannot convert type 'System.Windows.Forms.DataGridViewRow' to 'System.Data.DataRow'  

To answer Abel's question: The original type is desired because not all the columns are bound to the DataGridView. I need to duplicate some of the elements in this row and create a new based on user input.

Thanks again for your help. No solution thus far. How can I make this process easier?

On that last question, I can be short: just put a member variable to your form, set it to the datasource, wrap it in a property and call that when you set the DataSource to the grid and call it when you need a reference to the datasource like in the above event. Of course, the datatype of this property and the member type will be the TypeDataTable.

don't worry about having duplicate data (in case you were worrying, that is): in C#, basically in all OO languages, all that's stored is a reference to the table, the table itself is not copied.
I am a bit surprised about your casting problems. Are you positive about the contents of the row you are clicking on? Is it perhaps a header row or a footer row? It should be possible to downcast the object...

The error message clearly states that the real type of the (otherwise typeless) DataSource property is really a DataRowView. And I cast that all the time....without complaints... :S
mattjankowskiAuthor Commented:
Hi Abel,

As far as wrapping the DataSource in a property, I see what you are saying, but not all of my DataSource is displayed in the DataGridView. The Row Index I obtain at cell click does not always correlate to the Data in the Datasource.

As to the contents of the row, in the debugger when I navigate to MyDataGridView.Rows[] I can actually see the source row from the typed DataTable.

Thanks for your comments, if you have more please keep them coming!

> (TypedDataTableRow)dvrow.Row;

so stupid. I had been looking at these members because I remembered somehow it should be in there, only now I see that I had collapsed (hidden) the Properties in the help... That's what you get for working too long... lol

Glad you found it! As per the dilemma: no problem at all. Just click the "Accept Multiple Solutions" with one of the answers above. In the follow-up screen you will seen all the awardable comments and you can put in the amount you think each answer is worth. The total should add to the question total. The one comment you assign the highest will be considered "accepted solution", the others will be "assisted solution". The computer will choose in the event of a tie.

Note that the grade you give should be about the answers and/or the effort. It doesn't cost more points to assign higher grades. Just for your info, the two subjects causing the most confusion at EE: here are some closing tips and the 10pts must principle.

The screenshot is that other point of confusion to many: The red circle is for those cases where you found your solution yourself: it will select your comment as solution and you can then divide the points between the others. The green circle is what you're after.

Welcome at EE! ;-)

Ah yes, you are right, in your case the red one was more applicable, apologies for appearing as if that would be the bad choice...
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.