У меня есть datagridview, связанный с источником привязки и пару кнопок на форме. Одна кнопка добавляет элемент в источник привязки, а другой удаляет выбранный элемент. Также есть обработчик событий, который прослушивает событие CurrentChanged и обновляет статус Enabled кнопки Remove.Проблема привязки DataGridView: «Индекс -1 не имеет значения».
Все, что вам нравится, пока я не уйду, чтобы удалить последний элемент из datagridview. Потом я вижу очень некрасиво исключение:
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)
Я изолировали проблему в маленьком сценарии:
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)
{
// this line throws an exception when the last item is removed from
// the datagridview
btnRemove.Enabled = (m_bindingSource.Current != null);
}
}
public class StringValue
{
public string Value { get; set; }
public StringValue(string value)
{
Value = value;
}
}
Через чистого эксперимента, я обнаружил, что если я не изменить кнопку в обработчике событий CurrentChanged, тогда все работает нормально. Поэтому я подозреваю какой-то порядок операций. Но что? Почему попытка внести изменения, совершенно не связанные с проблемой datagridview, вызывает проблемы?
Чтобы сделать вещи еще более интересными, исключение обычно безвредно (или вообще не отображается), если программа запущена в VS с прикрепленным отладчиком. Но если он выполняется сам по себе, появляется окно с сообщением об исключении.
Я попытался обработать событие RowEnter в datagridview и обнаружил, что в этом случае он все еще считает, что он имеет строку и пытается извлечь текущий элемент из источника привязки, но m_bindingSource.Current
уже имеет значение null. Почему это только проблема при обработке события CurrentChanged?
Любая помощь была бы принята с благодарностью. Благодарю.
Вы действительно проверили, что это Button.Enabled и _not_ чтение BindSource.Current это критически важно? –
@ Хенк: похоже. Я разделил код установки Enabled на две строки: «var currentIsNotNull = m_bindingSource.Current! = Null; btnRemove.Enabled = currentIsNotNull;». Затем исключение вызывается установщиком btnRemove.Enabled. Тем не менее, если я вообще не основываю значение свойства Enabled на источнике привязки, все работает нормально, поэтому, возможно, это комбинация чтения и установщика Enabled. –
Я пробовал ваш код, и он работает отлично. Нет проблем, никаких исключений из отладчика визуальной студии и непосредственно из .exe. ... – pdiddy