I have a datagridview associated with a binding source and a couple of buttons in a form. One button adds an item to the binding source, and the other removes the selected item. There is also an event handler that listens for the CurrentChanged event and updates the Enabled status of the Remove button.
All this is hunky dory until I leave to remove the last item from datagridview. Then I see a very ugly exception:
at System.Windows.Forms.CurrencyManager.get_Item(Int32 index) at System.Windows.Forms.CurrencyManager.get_Current() at System.Windows.Forms.DataGridView.DataGridViewDataConnection.OnRowEnter(DataGridViewCellEventArgs e) at System.Windows.Forms.DataGridView.OnRowEnter(DataGridViewCell& dataGridViewCell, Int32 columnIndex, Int32 rowIndex, Boolean canCreateNewRow, Boolean validationFailureOccurred) at System.Windows.Forms.DataGridView.SetCurrentCellAddressCore(Int32 columnIndex, Int32 rowIndex, Boolean setAnchorCellAddress, Boolean validateCurrentCell, Boolean throughMouseClick) at System.Windows.Forms.DataGridView.SetAndSelectCurrentCellAddress(Int32 columnIndex, Int32 rowIndex, Boolean setAnchorCellAddress, Boolean validateCurrentCell, Boolean throughMouseClick, Boolean clearSelection, Boolean forceCurrentCellSelection)\r\n at System.Windows.Forms.DataGridView.MakeFirstDisplayedCellCurrentCell(Boolean includeNewRow) at System.Windows.Forms.DataGridView.OnEnter(EventArgs e) at System.Windows.Forms.Control.NotifyEnter() at System.Windows.Forms.ContainerControl.UpdateFocusedControl() at System.Windows.Forms.ContainerControl.AssignActiveControlInternal(Control value) at System.Windows.Forms.ContainerControl.ActivateControlInternal(Control control, Boolean originator) at System.Windows.Forms.ContainerControl.SetActiveControlInternal(Control value) at System.Windows.Forms.ContainerControl.SetActiveControl(Control ctl) at System.Windows.Forms.ContainerControl.set_ActiveControl(Control value) at System.Windows.Forms.Control.Select(Boolean directed, Boolean forward) at System.Windows.Forms.Control.SelectNextControl(Control ctl, Boolean forward, Boolean tabStopOnly, Boolean nested, Boolean wrap) at System.Windows.Forms.Control.SelectNextControlInternal(Control ctl, Boolean forward, Boolean tabStopOnly, Boolean nested, Boolean wrap) at System.Windows.Forms.Control.SelectNextIfFocused() at System.Windows.Forms.Control.set_Enabled(Boolean value) at Bug3324.Form1.HandleBindingSourceCurrentChanged(Object _sender, EventArgs _e) in D:\\Dev\\TempApps\\Bug3324\\Bug3324\\Form1.cs:line 41 at System.Windows.Forms.BindingSource.OnCurrentChanged(EventArgs e) at System.Windows.Forms.BindingSource.CurrencyManager_CurrentChanged(Object sender, EventArgs e) at System.Windows.Forms.CurrencyManager.OnCurrentChanged(EventArgs e)
I highlighted the problem in a small scenario:
private BindingSource m_bindingSource = new BindingSource(); public Form1() { InitializeComponent(); m_bindingSource.CurrentChanged += HandleBindingSourceCurrentChanged; m_bindingSource.DataSource = new BindingList<StringValue>(); dataGridView1.DataSource = m_bindingSource; btnAdd.Click += HandleAddClick; btnRemove.Click += HandleRemoveClick; } private void HandleRemoveClick(object _sender, EventArgs _e) { m_bindingSource.RemoveCurrent(); } private void HandleAddClick(object _sender, EventArgs _e) { m_bindingSource.Add(new StringValue("Some string")); } private void HandleBindingSourceCurrentChanged(object _sender, EventArgs _e) {
Thanks to pure experimentation, I found that if I did not change the state of the button in the CurrentChanged event handler, everything would be fine. Therefore, I suspect some order of operations. But what? Why is trying to make changes completely unrelated to the datagridview problem causing problems?
To make things even more interesting, an exception is usually harmless (or not displayed at all) if the program is running in VS with a debugger attached. But if it runs by itself, a window appears with an exception message.
I tried to handle the RowEnter event in a datagridview and found that in this case it still considers that it has a row and is trying to extract the current element from the binding source, but m_bindingSource.Current already null. Why is this only a problem when handling the CurrentChanged event?
Any help is appreciated. Thanks.