[英]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;
}
}
我認為像上面這樣的東西是你最好的鏡頭。
在嘗試了很多不同的事情之后,我找到了最簡單和(對我來說)最好的解決方案是檢查哪個控件集中在DataGridView
的RowValidating
事件中。 該解決方案正好解決了我遇到的問題:例如,通過單擊其他按鈕引發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.