EditingControlShowing события срабатывают несколько раз

У меня есть DGV в VB.Net 2008, подключенный к таблице Access DB. DGV не доступен только для чтения, но содержит столбцы, доступные только для чтения, за исключением одного, содержащего поле со списком. Поле со списком позволяет пользователю выбрать результат для этой конкретной строки, а затем программа копирует предварительно рассчитанное значение в столбец «Прибыль» в зависимости от элемента, выбранного в поле со списком. Затем пользователь нажимает кнопку «Сохранить», и БД обновляется (в настоящее время с помощью методов SQL в XSD).

Пока достаточно просто.

Вот код.

Private Sub DGUserBets_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DGUserBets.EditingControlShowing

    Dim combo As ComboBox = CType(e.Control, ComboBox)

    If (combo IsNot Nothing) Then

         // Remove an existing event-handler, if present, to avoid 
         // adding multiple handlers when the editing control is reused.
        RemoveHandler combo.SelectedIndexChanged, _
            New EventHandler(AddressOf DGUBStake_SelectedIndexChanged)

        // Add the event handler. 
        AddHandler combo.SelectedIndexChanged, _
            New EventHandler(AddressOf DGUBStake_SelectedIndexChanged)

    End If

End Sub


Private Sub DGUBStake_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)

    Dim myStatus As ComboBox = CType(sender, ComboBox)

    Dim row = DGUserBets.CurrentRow

    Select Case myStatus.SelectedIndex
        Case 0
            row.Cells("DGUBProfit").Value = 0
            // pending. no action
        Case 1
            row.Cells("DGUBProfit").Value = row.Cells("DGUBIfWin").Value
            // win
        Case 2
            // loses
            row.Cells("DGUBProfit").Value = row.Cells("DGUBIfLose").Value
        Case 3
            // void
            row.Cells("DGUBProfit").Value = 0
    End Select


End Sub

Проблема, с которой я столкнулся, заключается в том, что может показаться, что если пользователь выбирает желаемый результат из поля со списком, но НЕ нажимает Enter, а просто наводит курсор на другое поле со списком, чтобы снова выбрать результат для другой строки, первый обработчик событий не отключается. и, таким образом, события запускаются несколько раз. Затем это вызывает различные ошибки MsgBox по умолчанию и проблемы, когда пользователь пытается зафиксировать все изменения в программе DB / выходе и т. Д. И т. Д.

Что мне нужно сделать? Нужно ли мне .EndEdit где-нибудь подходить, чтобы заставить строку сохранить изменения? И как мне это назвать?

Спасибо.

Ответов (5)

Решение

Беглый взгляд на код вызывает следующий вопрос: если вы создаете новый обработчик событий при удалении существующего, будет ли он таким же?

У меня была аналогичная проблема, добавьте обработчик, CellLeave если e.ColumnIndex = myEditableColumn.Index выходящая ячейка - это ячейка, которую вы ищете (IE ), затем вызовите gv.EndEdit ()

Также я бы рекомендовал сделать переменные-члены обработчиков для назначения и удаления, потому что это кажется лучше, чем всегда говорить «Удалить новое» и «Добавить новое».

CKRet / Quintin, спасибо за быстрые ответы.

Быстрая попытка с этим кодом кажется лучше, а точки останова и пошаговое выполнение кода, похоже, запускают события правильно. Я новичок в .NET, поскольку последнее настоящее программирование на VB, которое я делал, было VB6, поэтому я не уверен, что это самый элегантный способ решения проблемы.

Также обратите внимание, что когда LastEventHandler = Nothing, вызов RemoveHandler не вызывает исключения, что довольно приятно.

Может быть, мне стоит предложить MS обновить эту статью.

Private Sub DGUserBets_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DGUserBets.EditingControlShowing

    Dim combo As ComboBox = CType(e.Control, ComboBox)

    Static LastEventHandler As EventHandler

    If (combo IsNot Nothing) Then

        // Remove an existing event-handler, if present, to avoid 
        // adding multiple handlers when the editing control is reused.
        RemoveHandler combo.SelectedIndexChanged, _
            LastEventHandler

        LastEventHandler = New EventHandler(AddressOf DGUBStake_SelectedIndexChanged)

        // Add the event handler. 
        AddHandler combo.SelectedIndexChanged, _
            LastEventHandler

    End If


End Sub

Я знаю, что это архаичный пост, но после того, как я полдня возился с этой же проблемой, я нашел способ решить эту проблему другим способом, поэтому я подумал, что им стоит поделиться.

Добавление второго обработчика для обработки события выхода из поля со списком, которое затем удаляет обработчик измененного selectedvalue. Кажется, что работает довольно гладко, и в отличие от другого найденного мной варианта дает желаемое результирующее действие (в отличие от удаления обработчика измененного значения в фактическом событии обработки, которое затем не сработает, если вы повторно выберете из того же поля со списком)

Private LastEventHandler As EventHandler = AddressOf Me.ComboBoxValueChanged

Private Sub dgvThisDatagrid_EditingControlShowing(sender As Object, e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles dgvOutstandingReminders.EditingControlShowing

    If TypeOf (e.Control) Is ComboBox Then
        Dim cboThisComboBox = DirectCast(e.Control, ComboBox)

        AddHandler cboThisComboBox.SelectedValueChanged, LastEventHandler

        AddHandler cboThisComboBox.Leave, AddressOf RemoveValueChangedHandler

    End If

End Sub

Private Sub ComboBoxValueChanged(ByVal sender As Object, ByVal e As System.EventArgs)

    If TypeOf (sender) Is ComboBox Then
        Dim cboThisComboBox = DirectCast(sender, ComboBox)

        MessageBox.Show("Value = " & cboThisComboBox.SelectedValue.ToString() & Environment.NewLine & "Text = " & cboThisComboBox.Text) ' Display index
    End If

End Sub

Private Sub RemoveValueChangedHandler(ByVal sender As Object, ByVal e As System.EventArgs)

    If TypeOf (sender) Is ComboBox Then
        Dim cboThisCombobox = DirectCast(sender, ComboBox)

        RemoveHandler cboThisCombobox.SelectedValueChanged, LastEventHandler
    End If

End Sub

Более простой код, который также, похоже, работает хорошо, как предлагает CKRet:

    Dim combo As ComboBox = CType(e.Control, ComboBox)

    If (combo IsNot Nothing) Then

       RemoveHandler combo.SelectedIndexChanged, AddressOf DGUBStake_SelectedIndexChanged

       AddHandler combo.SelectedIndexChanged, AddressOf DGUBStake_SelectedIndexChanged

    End If