我需要一个事件,当System.Windows.Forms.DataGridView
的当前行将要更改时触发,并允许我取消此更改,例如通过将EventArgs的Cancel-property设置为true。
我知道CurrentCellChanged
(调用事件时行已经更改)和RowLeave
(不可能取消离开操作)事件,但都没有提供我需要的内容。我也尝试使用RowValidating
事件,但是当该行要进行验证时(无意留下它)也会调用此事件,例如当我调用<ParentForm>.Validate()
时,这会导致很多困惑。
是否有任何其他可能性或干净(呃)解决方案来获得所需的行为?
答案 0 :(得分:1)
我认为你最好的选择是使用带有bool条件的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;
}
}
}
如果没有脏数据,无论谁调用验证,都不会生成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;
}
}
我认为上面的内容是你最好的镜头。
答案 1 :(得分:1)
在尝试了很多不同的事情之后,我找到了解决方案,最简单的(对我而言)最佳工作解决方案是检查哪个控件集中在RowValidating
的{{1}}事件中。此解决方案完全解决了我遇到的问题:例如,通过单击其他按钮引发了DataGridView
事件。仍有一些特殊情况会导致RowValidating
事件出现,即使当前行没有改变(例如,通过单击列标题对RowValidating
进行排序)但我认为我可以忍受这个小问题。也许.NET的未来版本将实现DataGridView
,其DataGridView
事件可以取消。
答案 2 :(得分:1)
刚刚遇到类似的问题,经过多次尝试,我唯一的工作就是使用&#34; Enter and Leave&#34;知道什么时候表单是NotActive以避免验证 - 幸运的是,点火顺序是在行\ col级别事件之前
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;
}
答案 3 :(得分:0)
更改 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