0

在 Visual Studio 2010 中开发的 Windows 窗体项目中,我有一个 DataGridView 绑定到一个 BindingSource,其 DataSource 是一个 BindingList(Of T)。T 是来自 Entity Framework 5 模型的实体。

我的实体实现了 INotifyPropertyChanged 和 IDataErrorInfo。

我的用户是 Excel 负责人,并坚持要求我将 Excel 数据粘贴到我们应用程序中使用的网格中。

因此,我制定了一些简单的规则。

  1. 尽可能模仿 Excel 中的复制和粘贴行为。
  2. 将数据粘贴到 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。如果没有,我一个人!

4

2 回答 2

1

当网格包含一列时,这可以完成工作。

假定开发人员正在正确处理 CellValidating 事件,这意味着如果验证失败,则取消该事件。

此例程非常类似于在 Excel 中观察到的复制和粘贴行为。

    Private Sub PasteFromClipboard(ByVal sender As Object, ByVal e As KeyEventArgs)
    Dim dgv = TryCast(sender, DataGridView)

    If Not IsNothing(dgv) AndAlso Clipboard.ContainsText Then
        If dgv.SelectedCells.Count > 0 Then
            Dim rowSplitter = {ControlChars.NewLine}
            Dim columnSplitter = {ControlChars.Tab}
            Dim topLeftCell = CopyPasteFunctions.GetTopLeftSelectedCell(dgv.SelectedCells)

            If Not IsNothing(topLeftCell) Then
                Dim clipBoardText = Clipboard.GetText(TextDataFormat.Text)
                Dim columnIndex = topLeftCell.ColumnIndex
                Dim rowIndex = topLeftCell.RowIndex
                Dim columnCount = dgv.Columns.Count
                Dim rows = clipBoardText.Split(rowSplitter, StringSplitOptions.None)

                For i = 0 To rows.Length - 2
                    'Split row into cell values
                    Dim values = rows(i).Split(columnSplitter)
                    Dim rowCount = dgv.Rows.Count

                    For j = 0 To values.Length - 1
                        If (i <= (rowCount - 1)) AndAlso ((j + 1) <= columnCount) Then
                            Dim cell = dgv.Rows(rowIndex + i).Cells(columnIndex + j)
                            dgv.CurrentCell = cell
                            dgv.BeginEdit(False)
                            dgv.EditingControl.Text = values(j)

                            If Not Me.Validate() Then
                                Exit Sub
                            Else
                                dgv.EndEdit()
                            End If
                        End If
                    Next
                Next
            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
于 2013-08-06T12:17:27.067 回答
0

我会解析数据并使用适合您的实体模型的新类型对象更新实体框架对象。然后只需保存实体对象并重新绑定您的 DGV。

于 2013-08-01T20:12:44.887 回答