Vb.net DataGridView.RowLeave在窗体按钮之前激发。鼠标单击

Vb.net DataGridView.RowLeave在窗体按钮之前激发。鼠标单击,vb.net,forms,datagridview,mouseclick-event,Vb.net,Forms,Datagridview,Mouseclick Event,我在任何地方都找不到关于这个的任何信息: 我有一个带有DataGridView和几个按钮的表单。选择datagridview的一行后,我单击表单上的一个按钮,dgv.RowLeave将在其他任何操作之前触发。它甚至在单击或鼠标单击之前触发 这是有道理的,但问题是RowLeave(ByVal sender作为对象,ByVal e作为DataGridViewCellEventArgs)的发送者是DataGridView,而不是按钮。因此,似乎不可能知道此时单击了什么按钮,因为sender和e都引用D

我在任何地方都找不到关于这个的任何信息: 我有一个带有
DataGridView
和几个按钮的表单。选择datagridview的一行后,我单击表单上的一个按钮,
dgv.RowLeave
将在其他任何操作之前触发。它甚至在单击或鼠标单击之前触发

这是有道理的,但问题是
RowLeave(ByVal sender作为对象,ByVal e作为DataGridViewCellEventArgs)
的发送者是DataGridView,而不是按钮。因此,似乎不可能知道此时单击了什么按钮,因为sender和e都引用DataGridView,而不是表单或按钮

单击事件将被触发,但仅在处理RowLeave后触发

那么,在RowLeave执行其他操作之前(在我的情况下,导致出现按钮。单击以永不处理),或者从RowLeave内部,是否有办法知道用户单击的位置

Class MainForm
' The form contains a DataGridView and btnQuit (and other buttons)

Private Sub dgv_RowLeave(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgv.RowLeave

  ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) ' This does validation and more. 
  ' But if btnQuit is clicked, I need to know here, or before RowLeave is
  ' triggered and NOT do this row validation.
  ' ...
End Sub

Private Sub Form_Click(sender As Object, e As EventArgs) Handles MyBase.Click
  Dim frm As Form
  frm = CType(sender, Form)
  ' Translated from Sach's comment below. Code never reaches this event
  '(RowLeave prevents it).
End Sub

Private Sub Quit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnQuit.MouseClick

  QuitPgm() ' Contains some more stuff.
  ' Also never executed, because RowLeave is handled first.

End Sub
End Class
Private Sub dgv_RowLeave(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgv.RowLeave

  ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) ' This does validation and more. 
  ' But if btnQuit is clicked, I need to know here, or before RowLeave is
  ' triggered and NOT do this row validation.
  ' ...
End Sub

我在这里使用的是
WinForms
,但想法是一样的

因此
事件
s附加到
控件
s。
按钮
是一个
控件
数据网格视图
也是一个控件。然后在代码背后有事件处理程序,它们本质上是与控制事件相关联的方法

因此,当您将
单击事件附加到按钮时,在幕后,
VB.NET
会创建一个
事件处理程序,如下所示:

private void button1_Click(object sender, EventArgs e)
{

}
现在,
sender
是一个对象,但实际上传递给它的是
DataGrid
。所以和你们的说法相反,在那个点上你们似乎不可能知道点击了什么按钮,你们可以知道是否点击了按钮。如果是,并且您附加了事件处理程序,则会调用它。例如,这将显示带有按钮文本的
消息框

private void button1_Click(object sender, EventArgs e)
{
    var btn = (Button)sender;
    MessageBox.Show(btn.Text);
}
因此,如果您想知道是否单击了
表单
,请附加
单击
事件处理程序:

private void Form1_Click(object sender, EventArgs e)
{
    var frm = (Form)sender;
    MessageBox.Show(frm.Text);
}

我不确定如何防止RowLeave事件中的按钮单击,但我认为应该使用RowValidating事件来验证DataGridView。假设我们有一个DataGridView,只有一列和一个按钮。验证为:列值不得大于100。如果我们将验证放在RowValidating事件中,则验证将在Leave事件之后、Validated事件之前触发。如果验证失败,则不会激发子序列事件

Public Class Form1

    Function ProgrammaticallyDoRowValidation(i As Integer) As Boolean
        If Convert.ToInt32(dgv(0, i).Value) > 100 Then
            Return False
        Else
            Return True
        End If
    End Function

    Private Sub dgv_RowValidating(sender As Object, e As DataGridViewCellCancelEventArgs) Handles dgv.RowValidating
        If Not ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) Then
            e.Cancel = True
        End If
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        MessageBox.Show("Buton clicked")
    End Sub

End Class
尝试运行代码并在列中输入大于100的值。无法单击该按钮,因为它未通过验证。但是,如果将
按钮的
CausesValidation
属性设置为
False
,则不会触发验证

事件的顺序如下所示:

使用键盘更改焦点时(TAB、SHIFT+TAB和 依此类推),通过调用Select或SelectNextControl方法,或 将ContainerControl.ActiveControl属性设置为当前 窗体中,焦点事件按以下顺序发生:Enter->GotFocus-> 离开->验证->验证->失去焦点

使用鼠标或调用焦点更改焦点时 方法,焦点事件按以下顺序发生:Enter->GotFocus ->LostFocus->离开->验证->验证

那么,在RowLeave离开之前,有没有办法知道用户单击的位置 做其他事情(在我的情况下,会导致按钮。单击 从未处理过),还是从内部处理

Class MainForm
' The form contains a DataGridView and btnQuit (and other buttons)

Private Sub dgv_RowLeave(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgv.RowLeave

  ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) ' This does validation and more. 
  ' But if btnQuit is clicked, I need to know here, or before RowLeave is
  ' triggered and NOT do this row validation.
  ' ...
End Sub

Private Sub Form_Click(sender As Object, e As EventArgs) Handles MyBase.Click
  Dim frm As Form
  frm = CType(sender, Form)
  ' Translated from Sach's comment below. Code never reaches this event
  '(RowLeave prevents it).
End Sub

Private Sub Quit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnQuit.MouseClick

  QuitPgm() ' Contains some more stuff.
  ' Also never executed, because RowLeave is handled first.

End Sub
End Class
Private Sub dgv_RowLeave(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgv.RowLeave

  ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) ' This does validation and more. 
  ' But if btnQuit is clicked, I need to know here, or before RowLeave is
  ' triggered and NOT do this row validation.
  ' ...
End Sub
这是一个有点混乱的解决方案,但是在事件中,您可以检查当前活动控件是否是您要测试的控件。在这种情况下,
集装箱控制
表格

Private Sub dgv_RowLeave(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) Handles dgv.RowLeave

    ProgrammaticallyDoRowValidation(dgv.CurrentRow.Index) ' This does validation and more. 
    ' But if btnQuit is clicked, I need to know here, or before RowLeave is
    ' triggered and NOT do this row validation.
    ' ...
    If Me.ActiveControl Is btnQuit Then
        ' do something
    End If
End Sub

任何和所有DGV事件的发送方都将是DGV。总是这样。但是按钮在表单上:如何捕获这些?不敢相信,因为其中一个在dgv上,所以无法知道在dgv之外单击了什么。单击事件和RowLeave事件是两个独立的事件。每个事件都有自己的发送者。在按钮点击事件中,发送者应该是按钮本身。为了更好地理解您的问题,请您向我们提供相关的代码片段,好吗?@Simo谢谢。我是否总是必须在代码前面手动添加4个空格?笨重…我试过了,但不起作用:按钮1\u单击和表单1\u单击都是在RowLeave后触发的。所以在我的例子中,这两个事件永远不会被处理,因为RowLeave(执行RowValidation和其他操作)会阻止按钮的代码被执行。我希望按钮具有优先级,即在行离开之前执行。这些事件是独立的。”DataGridView.RowLeave`在焦点离开
DataGridView
中的特定行时发生。当用户单击这些控件时,会出现
按钮
表单
单击。他们彼此无关。如果您从未关注过
DataGridView
FormLeave
甚至不会发生。而且没有理由认为
FormLeave
事件上的验证等应该停止触发其他事件。也许你应该展示你的代码。在上面的总结中补充。我仍然不明白你想说什么。当用户单击按钮时发生Click事件,当行选择更改时发生RowLeave。它们并不相互依赖。您的代码在RowLeave之后不会到达按钮事件。你希望它会这样吗?事实并非如此:如果我在RowLeave中的代码不起任何作用,则RowLeave将首先在鼠标单击按钮之后处理,然后,仅在单击事件之后处理。此外,它们以两种方式相互依赖:a)因为存在一个序列:在处理单击之前始终RowLeave;b)RowLeave事件中的代码导致单击未被处理。这就是为什么我希望看到序列行离开,然后单击反转,或者找到一种确定方向的方法