Problem information
I've added a CellValueChanged handler to a dataGridView, which has caused it to no longer load in properly.
The VB .net code that does the initialization looks like this (some identifier names changed):
Private Sub DesignMyView(ByRef dgv As DataGridView)
With CType(dgv.Columns(dgv.Columns.Add(New DataGridViewComboBoxColumn())), DataGridViewComboBoxColumn)
.DataSource = New DataView(dtMyView)
.ValueMember = "ID"
.DisplayMember = "Name"
.Name = "fkFirstColumn"
.HeaderText = "Hello"
.MaxDropDownItems = 20
.Width = 140
End With
What this is supposed to do is fairly simple: add a column to a grid view. But for some reason it won't properly execute. I've narrowed down the problem to the line .HeaderText = "Hello". If I do not set the header text, the code will run. However, when I do set the header text, some very strange things happen.
First, stepping through the code using F11 (Step Into), the code will run until the HeaderText line, and then, instead of proceeding to set the .MaxDropDownItems function, the next instruction VS shows me is a line in an entirely diffrent file: the .Show() function for the form containing this DataGridView. The thread that was setting up the contents of that form died and execution jumped back. In other words, something that is being done in the HeaderText setter that terminates the thread.
Interestingly, the HeaderText is being set, although this result is obviously undesirable: that view holds more than one column and now only the first is being displayed, and the form is missing half its contents because the init thread got terminated. There are no exceptions or messages of any kind, even when turning on every possible debug option.
Looking at the disassembly, VS produces:
1178: .HeaderText = "Hello"
00C19552 CC int 3
00C19553 15 BC B7 82 04 adc eax,482B7BCh
00C19558 8B 4D BC mov ecx,dword ptr [ebp-44h]
00C1955B 39 09 cmp dword ptr [ecx],ecx
00C1955D E8 DE 17 AB 7A call 7B6CAD40
00C19562 90 nop
When in the disassembly window, steps can be taken further. However, once it gets to call 7B6CAD40 (which is somewhere in forms.dll), VS refuses to display any more assembly, and after several seconds returns, with the thread gone. Suddenly, I'm now here:
203: frm.Show()
00BE5BE9 8B 4D C0 mov ecx,dword ptr [ebp-40h]
00BE5BEC 39 09 cmp dword ptr [ecx],ecx
00BE5BEE E8 61 4C 41 7A call 7AFFA854
00BE5BF3 90 nop
I stopped searching here for a bit (things got very complicated) and went with a different approach. Instead, adding a breakpoint to the new CellValueChanged event revealed that when HeaderText is changed, CellValueChanged is in fact called with a RowIndex = -1. Apparently the Header is considered a special kind of Cell with index of -1, and this internal implementation detail is unceremoniously forwarded to the user (also see here). Of course, this wasn't being checked, so the code inside the function threw an array out of bounds exception.
The question:
However, said exception was never really displayed, leading me on this wild goose chase, making finding and fixing the actual problem take far longer than it should.
- Where did my exception run off to?
- Why does it do this?
- How can I prevent this kind of red herring?
My hypothesis so far is that the exception in the CellValueChanged thread is causing the killing of the form init thread in the .NET runtime code here, but how and why?