事件,以阻止C#DataGridView更改当前行

本文关键字:C#DataGridView 事件 | 更新日期: 2023-09-27 18:24:44

我需要一个事件,当System.Windows.Forms.DataGridView的当前行将被更改时,该事件会触发,并允许我取消此更改,例如通过将EventArgs的cancel属性设置为true。

我知道CurrentCellChanged(调用事件时行已经更改)和RowLeave(不可能取消休假操作)事件,但它们都没有提供我需要的内容。我也尝试使用RowValidating事件,但当行即将被验证时(无意离开它),也会调用此事件,例如当我调用<ParentForm>.Validate()时,这会导致许多混淆。

是否有其他可能性或干净的解决方案来获得所需的行为?

事件,以阻止C#DataGridView更改当前行

刚刚遇到类似的问题,经过多次尝试,我唯一的解决办法是使用"Enter and Leave"来知道表单何时处于非活动状态,以避免验证-幸运的是,启动顺序在行''列级事件之前

HTH-Mike

    private bool IsActive = false;
    private void dgbList_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
    {
        if (IsActive)
        {
            if (Do_I_NeedTo_Cancel)
              e.Cancel = true;
        }
    }
    private void dgList_Leave(object sender, EventArgs e)
    {
        IsActive = false;
    }
    private void dgList_Enter(object sender, EventArgs e)
    {
        IsActive = true;
    }

我认为最好的选择是使用带有布尔条件的RowValidating来检查是否调用.Valide().

编辑

根据您最后的评论,为什么不添加dataGridView.IsCurrentRowDirty的检查?例如:

private void dataGridView1_RowValidating(object sender, DataGridViewCellCancelEventArgs e) {
    if (dataGridView1.IsCurrentRowDirty) {
        if (dataCheck())
            if (MessageBox.Show("Ok?", "Save?", MessageBoxButtons.YesNoCancel) == DialogResult.Cancel) {
                e.Cancel = true;
            }
    }
}

如果没有脏数据,无论谁调用验证,都不会进行dataCheck,也不会显示messageBox。

编辑

您可以将"if"子句替换为所需的任何检查,包括dataGridView2的检查。

如果您有非常复杂的需求,也可以扩展dataGridView控件。

编辑

我现在明白你的要求了。我认为没有一个快速而干净的解决方案。我会使用SelectionChanged事件,然后设置逻辑来阻止更改。类似于:

//rember the selection of the index
private int _currentIndex;
private bool _rollingBackSelection;
private void SelectionChanged(...){
     //when changing back to the selection in dgv1 prevent dgv2 check
     if (_rollingBackSelection) {
         _rollingBackSelection = false;
         return;
     }
     if (dgv2IsDirty()) {
          var result = MessageBox.Show("Ok?", "Save?", MessageBoxButtons.YesNoCancel);
          if (result == DialogResult.Cancel) {
             _rollingBackSelection = true;
             //rollback to the previous index
             dgv1.Rows[_currentIndex].Selected = true;
             return;
          }
          if (result == DialogResult.Yes)
             dgv2Save();
         dgv2Load();
         _currentIndex = dgv1.SelectedRows[0].Index;
     }
}

我认为像上面这样的事情是你最好的机会。

在尝试了很多不同的事情后,我得出了一个解决方案,即最简单和(对我来说)最好的工作解决方案是检查DataGridViewRowValidating事件中集中了哪个控件。这个解决方案正好解决了我遇到的问题:例如,RowValidating事件是通过单击其他按钮引发的。即使当前行没有更改(例如,通过单击列标题对DataGridView进行排序),仍有一些特殊情况会导致RowValidating事件发生,但我认为我可以接受这些小问题。也许.NET的未来版本将实现带有RowLeaving事件的DataGridView,该事件可以取消。

更改datagridview所选行不会自动清除任何文本框或任何其他表单控件,除非您为datagridview的"分配了事件处理程序;。SelectionChanged";清除数据的事件。

诀窍是,在清除表单数据或采取任何其他操作之前,必须检查所选行索引的有效性。如果表单控件中的数据已被修改,并且您希望将修改后的数据保留在表单控件中,则必须防止调用清除表单数据的过程。

我有下面的完整代码。这是可靠、稳定的,我想这是最简单的方法。创建一个Form,然后创建一个名为"的datagridview对象;DGVobj";以及一个名为"的按钮;按钮1";以测试代码"按钮1";切换布尔值以允许或不允许更改所选行。

"TakeAction()"只有当函数"0"时,程序才被执行;CheckIfDataHasChanged()";返回false。换句话说;TakeAction()"仅在表单数据未更改的情况下执行。如果表格数据被改变;选择上一行()"执行。此过程清除用户选择的行,然后再次选择前一行。有效行的索引存储在变量"中;PrvRowIdx"PrvRowIdx";如果您不想允许用户更改行选择,则需要。

你需要程序";DGV_CellBeginEdit()";以处理数据网格视图的";CellBeginEdit";事件如果数据发生更改,并且用户将编辑的单元格的行索引与用户已编辑数据的行的索引不同,则不希望用户编辑新行。

你看,我没有用";。RowValidating";事件及其事件取消方法。因为"。RowValidating";事件在"之前被激发";。SelectionChanged";事件,您将没有机会检查用户是否选择了新行。

布尔变量";bln_ clearingSelection"bln_CancelingEdit";,以及";bln_RowSelectionIsChanging;用于防止对过程的多次调用;StackOverFlow";例外这防止了";StackOverFlow";如果用户坚持通过不间断地单击行和单元格来更改所选行,则不会触发异常。

"DataGridViewTestForm;是一个窗体对象。

Public Class DataGridViewTestForm
    Private WithEvents DGVobj3 As New System.Windows.Forms.DataGridView
    Private dgvSelectedRow As System.Windows.Forms.DataGridViewRow
    Dim PrvRowIdx As Integer = -1
    Private bln_AllowRowChange As Boolean = False
    Private bln_clearingSelection As Boolean = False, bln_CancelingEdit As Boolean = False, bln_RowSelectionIsChanging As Boolean = False
    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()
        DGVobj.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect
        DGVobj.MultiSelect = False
        Button1.Text = "Not Allowed"
        CreateNewDataTable()
    End Sub
    Private Sub CreateNewDataTable()
        Dim objTable As New System.Data.DataTable
        Dim col1 As New System.Data.DataColumn("Column1")
        Dim col2 As New System.Data.DataColumn("Column2")
        objTable.Columns.Add(col1)
        objTable.Columns.Add(col2)
        Dim rw1 As System.Data.DataRow = objTable.NewRow
        Dim rw2 As System.Data.DataRow = objTable.NewRow
        Dim rw3 As System.Data.DataRow = objTable.NewRow
        objTable.Rows.Add(rw1)
        objTable.Rows.Add(rw2)
        objTable.Rows.Add(rw3)
        DGVobj.DataSource = objTable
    End Sub
    Private Sub DGV_SelectionChanged(sender As DataGridView, e As EventArgs) Handles DGVobj.SelectionChanged
        If (bln_clearingSelection Or bln_CancelingEdit Or bln_RowSelectionIsChanging) Then
            Exit Sub
        End If
        If CheckIfDataHasChanged() Then
            SelectThePreviousRow()
        Else
            TakeAction()
        End If
    End Sub
    Private Sub TakeAction()
        bln_RowSelectionIsChanging = True
        Dim dgvSRows As DataGridViewSelectedRowCollection = DGVobj.SelectedRows
        If dgvSRows IsNot Nothing Then
            If dgvSRows.Count = 1 Then
                dgvSelectedRow = dgvSRows.Item(0)
                PrvRowIdx = dgvSelectedRow.Index
            End If
        End If
        ClearFormControls()
        bln_RowSelectionIsChanging = False
    End Sub
    Private Sub ClearFormControls()
    End Sub
    Private Function SelectThePreviousRow() As Boolean
        bln_clearingSelection = True
        Dim bln_Reverted As Boolean = False
        Dim dgvRowCollection As DataGridViewSelectedRowCollection = DGVobj.SelectedRows
        If dgvRowCollection IsNot Nothing Then
            DGVobj.ClearSelection()
            bln_Reverted = True
        End If
        If PrvRowIdx >= 0 Then
            If DGVobj.Rows IsNot Nothing Then
                DGVobj.Rows.Item(PrvRowIdx).Selected = True
            End If
        End If
        bln_clearingSelection = False
        Return bln_Reverted
    End Function
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If bln_AllowRowChange Then
            bln_AllowRowChange = False
            Button1.Text = "Not Allowed"
        Else
            bln_AllowRowChange = True
            Button1.Text = "Allowed"
        End If
    End Sub
    Private Sub DGV_CellBeginEdit(sender As DataGridView, e As DataGridViewCellCancelEventArgs) Handles DGVobj.CellBeginEdit
        Dim bln_CancelingEdit = True
        Dim bln_EditWasCanceled As Boolean = False
        Dim RowIdx As Integer = e.RowIndex
        Dim dgvRowCollection As DataGridViewSelectedRowCollection = DGVobj.SelectedRows
        If dgvRowCollection IsNot Nothing Then
            Dim rwCnt As Integer = dgvRowCollection.Count
            If rwCnt = 1 Then
                If PrvRowIdx <> RowIdx Then
                    e.Cancel = True
                    bln_EditWasCanceled = True
                End If
            Else
                e.Cancel = True
                bln_EditWasCanceled = True
            End If
        Else
            e.Cancel = True
            bln_EditWasCanceled = True
        End If
        bln_CancelingEdit = False
    End Sub
    Private Function CheckIfDataHasChanged() As Boolean
        If bln_AllowRowChange Then
            Return False
        Else
            Return True
        End If
    End Function
End Class