【问题标题】:EditingControlShowing events firing multiple timesEditingControlShowing 事件触发多次
【发布时间】:2009-02-24 17:13:14
【问题描述】:

我在 VB.Net 2008 中有一个连接到 Access DB 表的 DGV。 DGV 不是只读的,而是充满了只读列,除了一个包含组合框的列。组合框允许用户为该特定行选择结果,然后程序根据组合框中选择的项目将预先计算的值复制到“利润”列中。然后用户点击保存按钮并更新数据库(目前通过 XSD 中的 SQL 方法)。

到目前为止已经足够简单了。

这里是代码。

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/exit 程序等时引发问题。

我需要做什么?我是否需要 .EndEdit 在适当的地方强制该行保存更改?我应该在哪里称呼它?

谢谢。

【问题讨论】:

    标签: vb.net visual-studio-2008 datagridview event-handling editcontrol


    【解决方案1】:

    快速浏览一下代码会提出这个问题: 如果您在删除现有事件处理程序时创建一个新的事件处理程序,它是同一个吗?

    【讨论】:

    • 嗯.. EditControlShowing 代码来自 MSDN。你认为我可能没有正确实施它吗? msdn.microsoft.com/en-us/library/…
    • 当您使用 AddHandler 时,您不会将创建的 EventHandler 保存在任何地方。这样做并在调用 RemoveHandler 时使用该引用。
    • 另一方面:你甚至不需要使用 New EvenHandler: RemoveHandler combo.SelectedIndexChanged, AddressOf DGUBStake_SelectedIndexChanged AddHandler combo.SelectedIndexChanged, AddressOf DGUBStake_SelectedIndexChanged 应该做。
    【解决方案2】:

    我遇到了类似的问题,如果要退出的单元格是您要查找的单元格(即 e.ColumnIndex = myEditableColumn.Index),请为 CellLeave 添加一个处理程序,然后调用 gv.EndEdit()

    另外,我建议将处理程序成员变量用于分配和删除,因为它看起来比总是说 Remove New 和 Add New 更好。

    【讨论】:

    • 啊,我明白了!我现在已经使用我在下面发布的代码保存了 Handler 变量。你能给我更多关于 CellLeave 处理程序的线索吗?谢谢!
    • 对不起 - 我一开始看错了,现在明白你的意思了,我只需要在 DGV 的 _CellLeave 中添加代码,不是吗?谢谢。
    • 对不起,我有一段时间分心了,是的,如果您在 DGV 的 CellLeave 中添加一个处理程序,然后您可以在它是您尝试强制更改的特定列时处理......当它遇到并遇到条件调用 DGV 上的 EndEdit,它应该强制进行更改。
    【解决方案3】:

    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
    

    【讨论】:

    • 您是否尝试过我的其他建议,根本不使用 New EventHandler?
    • 哦,是的,我已经尝试过了,确实也很有效;我想我会使用它,因为它是更简单的代码!谢谢!!
    【解决方案4】:

    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
    

    【讨论】:

      【解决方案5】:

      我知道这是一个过时的帖子,但是在同一个问题混了半天之后,我找到了另一种方法来解决这个问题,所以我认为值得分享。

      添加第二个处理程序来处理组合框的离开事件,然后删除选定值更改的处理程序。看起来工作起来非常流畅,并且与我发现的另一个选项不同,它给出了所需的结果操作(不像在实际处理事件中删除值更改处理程序,如果您从同一个组合框中重新选择则不会触发)

      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
      

      【讨论】:

        猜你喜欢
        • 2016-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多