Ctrl+Shift+B

Compilations by Steve Majewski
posts - 205, comments - 67, trackbacks - 2

My Links

News


The ideas contained herein are mine and mine alone, and do not reflect the beliefs of my employer, family, friends, faith, or society in general. Reader discretion advised.


Memberships

Avanade
Solutions Developer

Xbox Live Gamer Card

Article Categories

Archives

Post Categories

Resources

Blogroll

Podcasts

Miscellaneous

DataGridView Reentrant Call Nightmare

The story begins with the QA team finding a bug. The description of the bug appears quite simple. When the user clicked on a cell in a DataGridView on the form then closed the form using the X, reopening the form would throw an unhandled exception. "No problem," I think to myself. Little did I know the adventure on which I was about to embark.

Naturally, my first stop at debugging was to get the actual error that occurred. I place it here in the hopes that the wary developer scouring the web for a solution to a particularly nasty bug (get on with it) will find it and be saved:

System.InvalidOperationException was unhandled
Message="Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore function."

The error message appeared simple enough. It even contained pretty words that make it much easier when finding solutions on Google (ahem...I mean MSN Search). Sadly, my search yielded me annoying solutions with no results.

Let me start (you're starting now?) by explaining what is happening. When the X button is hit, the form's focus does not change from the DataGridView. As a result, the grid remains in an unedited state. This particular form was being reused as a dialog, so the next time the form opened and code tried to change the grid's data, the error would occur.

The error is caused by an infinite loop. The cell on the grid is trying to change, thus calling the SetCurrentCellAddressCore, which in turn raises some other event that calls the SetCurrentCellAddressCore and so on and so forth. .NET detects the loops and gracefully crashes headlong into the ground like an ogre on ice skates.

The craziest part was the error would only occur when the application was run directly. When I ran it through VS in debug mode, it would continue on its merry way like nothing happened. Wrapping the offending call in a TRY...CATCH block also did not work. The interactive debugger would catch the exception but running the application direct (off the same compile, mind you) would throw the error every time despite the TRY...CATCH.

One solution I found involved deriving my own DataGridView class and overriding the SetCurrentCellAddressCore method. A property was added the would indicate whether or not the form was reloading data and prevent the reentrant call. While this worked for me when setting the grid's DataSource to null, it caused an IndexOutOfRangeException when I tried setting the DataSource later.

During my debugging, I could see good and well that the grid thought it was being edited thanks to the IsCurrentCellInEditMode property. I tried calling the CancelEdit, EndEdit, and even NotifyCurrentCellDirty methods, but the grid remained in edit mode. I tried directly setting the CurrentCell to null. No dice. The grid refused to realize that it really wasn't being edited.

Finally, light dawned on marble head. The problem is the grid is still active when the form is closed. What if I just selected another control when closing the form? There was no reason not to set the focus back to the first control on the form so that the next time the form opened it would be selected.

Even though I had code in place to switch the control focus, it was triggered when the form was opened (activated really) rather than when it was closed. The only thing I can deduce is the grid goes into a strange limbo if the form is closed whilst it is in edit mode. I created a FormClosing event and added the one line of code to select the first control on the form. That was enough to switch the grid out of edit mode so that it could be manipulated the next time the form was opened.

So what started as an easy looking bug ended with an easy solution with about 10 hours of hair pulling antics piled up in the middle. Either way, I still got the warm fuzzies when I saw it work. That is the mark of a true developer.

Technorati tags: , ,

Print | posted on Thursday, May 17, 2007 9:01 AM

Feedback

Gravatar

 re: DataGridView Reentrant Call Nightmare

this situation is my problem , but does not understanding. will give me to sample
10/26/2007 12:04 PM | glenda

 re: DataGridView Reentrant Call Nightmare

A sample isn't going to do much good. Add a FormClosing event to the form containing the DataGrid and in the event set the focus to another control. It doesn't matter which control as long as it is NOT the DataGrid.
11/7/2007 9:50 AM | Steve

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 1 and 1 and type the answer here:

Powered by: