簡體   English   中英

防止 C# DataGridView 更改當前行的事件

[英]Event to prevent C# DataGridView from changing the current row

我需要一個在System.Windows.Forms.DataGridView的當前行將被更改時觸發的事件,它允許我取消此更改,例如通過將 EventArgs 的 Cancel-property 設置為 true。

我知道CurrentCellChanged (在調用事件時行已經改變)和RowLeave (不可能取消離開操作)事件,但都沒有提供我需要的。 我也嘗試使用RowValidating事件,但是當行將被驗證(無意離開它)時也會調用此事件,例如當我調用<ParentForm>.Validate() ,這會導致許多混亂。

是否有其他可能性或干凈(呃)解決方案來獲得所需的行為?

剛剛遇到了類似的問題,經過多次嘗試,我唯一的解決方法是使用“進入和離開”來了解表單何時處於非活動狀態以避免驗證 - 幸運的是,觸發順序在行\\列級事件之前

HTH - 邁克

    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 來檢查你是否調用了 .Validate()。

編輯

根據您的最后一條評論,為什么不添加對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;
            }
    }
}

如果沒有臟數據,無論是誰調用驗證都不會進行數據檢查,也不會出現消息框。

編輯

您可以用您想要的任何檢查替換“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,然后創建一個名為“DGVobj”的datagridview 對象和一個名為“Button1”的按鈕來測試代碼。 “Button1”切換布爾值以允許或不允許更改所選行。

“TakeAction()”過程僅在函數“CheckIfDataHasChanged()”返回false時才執行。 換言之,“TakeAction()”僅在表單數據未更改時執行。 如果表單數據發生更改,則執行過程“SelectThePreviousRow()”。 此過程清除用戶選擇的行的選擇,並再次選擇前一行。 有效行的索引存儲在變量“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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM