在 Visual Studio 2010 中开发的 Windows 窗体项目中,我有一个 DataGridView 绑定到一个 BindingSource,其 DataSource 是一个 BindingList(Of T)。T 是来自 Entity Framework 5 模型的实体。
我的实体实现了 INotifyPropertyChanged 和 IDataErrorInfo。
我的用户是 Excel 负责人,并坚持要求我将 Excel 数据粘贴到我们应用程序中使用的网格中。
因此,我制定了一些简单的规则。
- 尽可能模仿 Excel 中的复制和粘贴行为。
- 将数据粘贴到 DataGridView 中的新行应创建并验证网格中表示的类型的新实体。
我已经走了很长一段路,但现在遇到了一些我无法弄清楚的事情。
从我能找到的信息来看,很明显,当粘贴到绑定网格时,底层数据源应该是您编辑和创建的目标。
还是应该?
我已经尝试了两种方法。
当定位单元格本身时,我希望我可以编写例程,以便在需要时触发 DataGridView 中内置的验证事件,无论我是在编辑现有行还是创建新行。
我很快发现它没有按预期工作,因为 CellValidating 在单元格失去焦点之前不会触发。
粘贴时,我想在将值粘贴到单元格时验证单元格 - 如果失败则取消其余的粘贴操作。
当定位基础数据源(将行的 DataBoundItem 转换为适当的实体类型)时,我可以从剪贴板数据创建新实体并在将更改提交到 DbContext 之前验证它们。
无论哪种情况,当验证失败时,DataGridView 似乎都丢失了单元格的先前值。
如果验证失败,则会提示用户并退出例程。我希望用户能够按 Esc 键返回单元格的先前值,但单元格仍然为空。
有谁知道为什么以前的值在以编程方式编辑单元格的值时不再可用?
这是我目前正在做的事情。我通过调用表单的 .Validate 方法来强制触发验证事件。我不知道我是否应该这样做。这是不完整的,因为我还没有处理新的行:
Private Sub PasteFromClipboard(ByVal sender As Object, ByVal e As KeyEventArgs)
Dim dgv = TryCast(sender, DataGridView)
If Not IsNothing(dgv) Then
If dgv.SelectedCells.Count > 0 Then
Dim rowSplitter = {ControlChars.Cr, ControlChars.Lf}
Dim columnSplitter = {ControlChars.Tab}
Dim topLeftCell = CopyPasteFunctions.GetTopLeftSelectedCell(dgv.SelectedCells)
If Not IsNothing(topLeftCell) Then
Dim data = Clipboard.GetData(DataFormats.Text)
If Not IsNothing(data) Then
Dim columnIndex = topLeftCell.ColumnIndex
Dim rowIndex = topLeftCell.RowIndex
Dim columnCount = dgv.Columns.Count
Dim rowCount = dgv.Rows.Count
'Split clipboard data into rows
Dim rows = data.ToString.Split(rowSplitter, StringSplitOptions.RemoveEmptyEntries)
For i = 0 To rows.Length - 1
'Split row into cell values
Dim values = rows(i).Split(columnSplitter)
For j = 0 To values.Length - 1
If (j <= (columnCount - 1)) AndAlso (i <= (rowCount - 1)) Then
Dim cell = dgv.Rows(rowIndex + i).Cells(columnIndex + j)
dgv.CurrentCell = cell
dgv.BeginEdit(False)
cell.Value = values(j)
If Not Me.Validate() Then
dgv.CancelEdit()
Exit Sub
Else
dgv.EndEdit()
End If
Else
Debug.Print(String.Format("RowIndex: {0}, ColumnIndex: {1}", i, j))
End If
Next
Next
End If
End If
End If
End If
End Sub
Public Module CopyPasteFunctions
Public Function GetTopLeftSelectedCell(ByVal cells As DataGridViewSelectedCellCollection) As DataGridViewCell
If Not IsNothing(cells) AndAlso cells.Count > 0 Then
Dim cellList = (From c In cells.Cast(Of DataGridViewCell)()
Order By c.RowIndex, c.ColumnIndex
Select c).ToList
Return cellList(0)
End If
Return Nothing
End Function
End Module
感谢您对此的任何帮助。希望其他人正在使用 EF5 和 Winforms。如果没有,我一个人!