【问题标题】:Pasting new records to a Bound DataGridView将新记录粘贴到绑定的 DataGridView
【发布时间】:2019-09-16 18:38:52
【问题描述】:

抱歉,如果这已经被问到了。如果是这样,我无法找到一个简单的解决方案。我试图允许用户在 DataGridView 中复制/粘贴多条记录(数据的内存副本,稍后在用户单击保存按钮时保存)并且找不到任何有效的东西。这可能是因为我对这一切有些不理解。

我使用 Visual Studio 的拖动/表格设置了一个标准的编辑表单,因此它使用 BindingSource 控件和所有其他控件。当手动在新行中逐个输入内容时它工作得很好,因此它似乎设置正确,但是当使用代码添加记录(或多个记录)时,似乎没有任何工作。

我在下面的代码中尝试了一些内容。有人可以请至少引导我朝着正确的方向前进吗?粘贴多条记录并没有那么难。

我在用户按下 Control-V 时运行此命令(剪贴板正确保存分隔字符串):

Private Sub PasteClipboard()
    If Clipboard.ContainsText Then
        Dim sLines() As String = Clipboard.GetText.Split(vbCrLf)
        For Each sLine As String In sLines
            Dim Items() As String = sLine.Split(vbTab)

            Dim drv As DataRowView = AdjustmentsBindingSource.AddNew()
            drv.Item(1) = Items(0)
            drv.Item(2) = Items(1)
            drv.Item(3) = Items(2)
            drv.Item(4) = Items(3)
'Error on next line : Cannot add external objects to this list.
            AdjustmentsBindingSource.Add(drv)

        Next
    End If
End Sub

编辑

(绑定源绑定到数据适配器,数据适配器绑定到 mdb 文件中的表,如果这有助于理解)

我将代码的内部部分调整为:

            If (RowHasData(Items)) Then
                Dim drv As DataRowView = AdjustmentsBindingSource.AddNew()
                drv.Item("FontName") = Items(0)
                drv.Item("FontSize") = Items(1)
                drv.Item("LetterCombo") = Items(2)
                drv.Item("Adjustment") = Items(3)
                drv.Item("HorV") = Items(4)
            End If

它有点工作,但它还在 2 个新行之前添加了一个空白行。不知道这是从哪里来的,因为我什至包括了你的 RowHasData() 例程......

【问题讨论】:

  • 你需要解释当你执行你的代码时实际发生了什么。
  • 谢谢。我更新了它,试图让它更清楚。信息够不够?

标签: vb.net datagridview bindingsource


【解决方案1】:

我认为“attemp3”应该可以工作,但是尚不清楚AdjustmentsBindingSource’s DataSource 是“什么”。是List<T> 还是DataTable

如果我将 BinngSource.DataSource 设置为 DataTable,则尝试 3 似乎有效。下面是一个有效的例子。

Private Sub PasteClipboard2()
    If Clipboard.ContainsText Then
        Dim sLines() As String = Clipboard.GetText.Split(vbCrLf)
        For Each sLine As String In sLines
            Dim Items() As String = sLine.Split(vbTab)
            If (RowHasData(Items)) Then
                Dim drv As DataRowView = AdjustmentsBindingSource.AddNew()
                drv.Item("FontName") = Items(0)
                drv.Item("FontSize") = Items(1)
                drv.Item("LetterCombo") = Items(2)
                drv.Item("Adjustment") = Items(3)
                drv.Item("HorV") = Items(4)
            End If
        Next
    End If
End Sub

这似乎在我的测试中有效。我添加了一个小函数(RowHasData)来避免格式​​错误的字符串导致问题。它只是检查大小(至少 5 个项目)并检查以确保一行实际上有“一些”数据。如果一行只是空字符串,则将其忽略。

Private Function RowHasData(items As String())
    If (items.Count >= 5) Then
        For Each item In items
            If (item <> "") Then Return True
        Next
    End If
    Return False
End Function

我猜想将新行“直接”添加到BindingSourceDataSource. 中同样容易。在下面的示例中,代码是将行“直接”添加到DataTable 中用作DataSourceBindingSource. 我相信您可以通过简单地将新对象添加到列表中来对List&lt;T&gt; 做同样的事情。下面是使用BindingSourceDataTable 的完整示例。这只是将行添加到表格的底部。

Dim gridTable1 As DataTable

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    PasteClipboard()
End Sub

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    gridTable1 = GetTable()
    FillTable(gridTable1)
    AdjustmentsBindingSource.DataSource = gridTable1
    AdjustmentsDataGridView.DataSource = AdjustmentsBindingSource
End Sub

Private Function GetTable() As DataTable
    Dim dt = New DataTable()
    dt.Columns.Add("FontName", GetType(String))
    dt.Columns.Add("FontSize", GetType(String))
    dt.Columns.Add("LetterCombo", GetType(String))
    dt.Columns.Add("Adjustment", GetType(String))
    dt.Columns.Add("HorV", GetType(String))
    Return dt
End Function

Private Sub FillTable(dt As DataTable)
    For index = 1 To 10
        dt.Rows.Add("Name_" + index.ToString(), "Size_" + index.ToString(), "Combo_" + index.ToString(), "Adjust_" + index.ToString(), "HorV_" + index.ToString())
    Next
End Sub

Private Sub PasteClipboard()
    If Clipboard.ContainsText Then
        Dim sLines() As String = Clipboard.GetText.Split(vbCrLf)
        Try
            Dim dataRow As DataRow
            For Each sLine As String In sLines
                Dim Items() As String = sLine.Split(vbTab)
                If (RowHasData(Items)) Then
                    dataRow = gridTable1.NewRow()
                    dataRow("FontName") = Items(0)
                    dataRow("FontSize") = Items(1)
                    dataRow("LetterCombo") = Items(2)
                    dataRow("Adjustment") = Items(3)
                    dataRow("HorV") = Items(4)
                    gridTable1.Rows.Add(dataRow)
                End If
            Next
        Catch ex As Exception
            MessageBox.Show("Error: " + ex.Message)
        End Try
    End If
End Sub

Private Function RowHasData(items As String())
    If (items.Count >= 5) Then
        For Each item In items
            If (item <> "") Then Return True
        Next
    End If
    Return False
End Function

希望代码有所帮助……

最后但重要的是,我只是猜测您可能没有“测试”用户可以“选择”数据的不同方式以及其他应用程序“如何”“复制”所选数据。我之前使用 WIN-OS“剪贴板”的测试有时会产生意想不到的结果。例如,如果用户使用“Ctrl”键选择多个项目以“添加”到选择,如果选择不连续,则剪贴板中会出现额外的行。我的重点是使用操作系统剪贴板是古怪的恕我直言。我建议对用户选择数据的“不同”方式进行大量测试。如果这不是问题,那么上面的代码应该可以工作。

【讨论】:

  • 如果您有时间看,我再次更新了这个问题。由于某种原因,它添加了一个额外的空白行。我尽量不添加太多额外/新的东西,以保持它足够简单,让我理解。
  • 只有当我在粘贴之前本能地突出显示新行时才会出现空白行,所以我想我只需要弄清楚为什么会发生这种情况以及如何防止它。
  • 正如我最后评论的那样,我在空字符串的一个字段中具有相同的vblf(换行符),这取决于我如何“选择”文本。我只是从另一个网格和 Excel 电子表格中复制。我得到了不同的结果,因此使用了RowHasData 方法。我相信,如果您跳下这个兔子洞,您会在测试操作系统剪贴板时进行更多检查。
  • 这是我从使用操作系统的“剪贴板”的角度发表评论的原因之一。您几乎必须遵循 IT 想要做的事情。正如所见,根据用户选择数据的“方式”或其他应用程序如何处理向操作系统“复制”命令的方式,可能会产生不同的结果。另外,我认为必须进行大量检查,因为用户基本上可以复制任何内容。如果用户正在处理另一个DataGridView,那么我建议使用网格SelectedRows 集合来消除使用操作系统剪贴板所需的大量检查。
  • 我想我只是想保持简单,让它像 Excel 一样工作,因为这是用户习惯处理的。 - 复制 4 个现有行并调整一些结果。有没有一种简单的方法可以做到这一点?因为作为一个新的 .NET 开发人员,你的长版答案中的所有这些额外内容让我头晕目眩。
猜你喜欢
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
相关资源
最近更新 更多