事件,以阻止C#DataGridView更改当前行
本文关键字:C#DataGridView 事件 | 更新日期: 2023-09-27 18:24:44
我需要一个事件,当System.Windows.Forms.DataGridView
的当前行将被更改时,该事件会触发,并允许我取消此更改,例如通过将EventArgs的cancel属性设置为true。
我知道CurrentCellChanged
(调用事件时行已经更改)和RowLeave
(不可能取消休假操作)事件,但它们都没有提供我需要的内容。我也尝试使用RowValidating
事件,但当行即将被验证时(无意离开它),也会调用此事件,例如当我调用<ParentForm>.Validate()
时,这会导致许多混淆。
是否有其他可能性或干净的解决方案来获得所需的行为?
刚刚遇到类似的问题,经过多次尝试,我唯一的解决办法是使用"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;
}
}
我认为像上面这样的事情是你最好的机会。
在尝试了很多不同的事情后,我得出了一个解决方案,即最简单和(对我来说)最好的工作解决方案是检查DataGridView
的RowValidating
事件中集中了哪个控件。这个解决方案正好解决了我遇到的问题:例如,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