【问题标题】:Datagridview to Clipboard OptimizationDatagridview 到剪贴板优化
【发布时间】:2015-09-22 15:49:40
【问题描述】:

我不是在问如何将数据网格复制到我的剪贴板,而是更多地优化我的代码。

这是我必须将我的 datagridview 复制到剪贴板的内容,以便我可以将其内容粘贴到 excel 中。

    Dim dgv As DataGridView = dgvData
    Dim s As String = ""
    Dim oCurrentCol As DataGridViewColumn    'Get header
    oCurrentCol = dgv.Columns.GetFirstColumn(DataGridViewElementStates.Visible)
    oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None)

    Do
        s &= oCurrentCol.HeaderText & Chr(Keys.Tab)
        oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None)
    Loop Until oCurrentCol Is Nothing

    s = s.Substring(0, s.Length - 1)
    s &= Environment.NewLine    'Get rows
    For Each row As DataGridViewRow In dgv.Rows
        oCurrentCol = dgv.Columns.GetFirstColumn(DataGridViewElementStates.Visible)
        oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None)
        Do
            If row.Cells(oCurrentCol.Index).Value IsNot Nothing Then
                s &= row.Cells(oCurrentCol.Index).Value.ToString
            End If
            s &= Chr(Keys.Tab)
            oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None)
        Loop Until oCurrentCol Is Nothing
        s = s.Substring(0, s.Length - 1)
        s &= Environment.NewLine
    Next    'Put to clipboard

    Dim o As New DataObject
    o.SetText(s)
    Clipboard.SetDataObject(o, True)

这很好用!完全符合我的要求,包括省略第一列,并且在粘贴到 Excel 时看起来很完美。

现在我遇到的问题是它非常慢。在我的开发计算机上,复制大约 10,000 行 10 列大约需要两分钟。在我们的一些较旧的服务器上,我让它运行了十多分钟,最终只是终止了该进程,因为它花费了很长时间。

我不知道我可以做些什么来加快这个过程。任何帮助表示赞赏!

谢谢!

【问题讨论】:

  • 在那个大小下,跳过剪贴板并将内容写入文件可能会更好。也就是说,StringBuilder 可能会有所帮助。
  • 除了非常非常基础的 StringBuilder 之外,我没有大量的经验,但是有没有办法可以将内容附加到字符串中,以便用户能够将内容粘贴到 Excel 中电子表格来模仿 datagridview?
  • StringBuilder 使用起来非常简单:s.Append(blah blah blah) 最后将其转换为字符串:s.ToString()
  • 首先,您的GetFirstColumn(和类似的)方法似乎效率很低。您最好只遍历所有列/行并通过检查相应的属性(“可见”?)来选择适当的列/行。另一方面,您与 Excel 进行通信的方式当然并不理想。主要是在涉及这么多记录时。除非在非常特定的条件下(并且数据大小要小得多),否则依赖剪贴板不应该是一种选择。为什么不在列/行循环时直接写入 Excel?
  • 此外,如果您使用DataSource 来填充DataGridView,您可能更愿意直接依赖它,因为关联的对象(DataTable)比DataGridView 更具适应性.

标签: vb.net winforms


【解决方案1】:

这是我用来通过剪贴板将数据移动到 Excel 的代码。

   Private Sub tsbtnCopy_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tsbtnCopy.Click
    Try
        If dgv01.Rows.Count = 0 Then Exit Sub
        dgv01.SuspendLayout()
        dgv01.RowHeadersVisible = False
        If dgv01.SelectedRows.Count = 0 Then dgv01.SelectAll()
        Clipboard.SetDataObject(dgv01.GetClipboardContent())
        dgv01.ClearSelection()
    Catch ex As Exception
        MsgBox(ex.Message)
    Finally
        dgv01.RowHeadersVisible = True
        dgv01.ResumeLayout()
    End Try
End Sub

【讨论】:

  • 这可能可行,但由于我的应用程序的功能,我无法使用 SelectAll()。
  • 您可以使用GetClipboardContent 将数据快速获取到由vbNewline 和vbTab 分隔的本地字符串中。 ClipboardCopyMode 也可能有用。
【解决方案2】:

所以,鉴于我的情况,我结束了用 StringBuilder 交换我的字符串字符串。为了复制 ~10000 我从 2 分钟到几乎瞬间!在阅读了字符串生成器的工作原理之后,它似乎对我正在做的事情非常有效。我非常惊讶地看到它实际上有什么不同!这是我所做的一些小改动。

即使在我们的旧服务器上,它也几乎是瞬间完成的,与 15 分钟以上的时间相比,这是巨大的。

    Dim dgv As DataGridView = dgvData
    Dim s As New StringBuilder
    Dim oCurrentCol As DataGridViewColumn = dgv.Columns.GetFirstColumn(DataGridViewElementStates.Visible)   'Get header

    oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None)

    Do
        s.Append(oCurrentCol.HeaderText & Chr(Keys.Tab))
        oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None)
    Loop Until oCurrentCol Is Nothing

    s.Append(Environment.NewLine)    'Get rows
    For Each row As DataGridViewRow In dgv.Rows
        oCurrentCol = dgv.Columns.GetFirstColumn(DataGridViewElementStates.Visible)
        oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None)
        Do
            If row.Cells(oCurrentCol.Index).Value IsNot Nothing Then
                s.Append(row.Cells(oCurrentCol.Index).Value.ToString)
            End If
            s.Append(Chr(Keys.Tab))
            oCurrentCol = dgv.Columns.GetNextColumn(oCurrentCol, DataGridViewElementStates.Visible, DataGridViewElementStates.None)
        Loop Until oCurrentCol Is Nothing
        s.Append(Environment.NewLine)
    Next    'Put to clipboard

    Dim o As New DataObject
    o.SetText(s.ToString())
    Clipboard.SetDataObject(o, True)

【讨论】:

    【解决方案3】:

    如果您要在 GridView 和 Excel 之间使用这么多行,我将永远不会使用剪贴板(您可能会在某些时候遇到障碍,内存方面的说法)。

    相反,我将创建一个 CSV 并直接在 Excel 中打开它。您甚至可以使用 ShellExecute 自动打开它。

    还有几个类似的问题,比如:

    [C#] Generating CSV file from SqlDataSource/GridView

    [VB.NET] Trying to export asp.net gridview to a .csv file

    【讨论】:

      【解决方案4】:
      1. 优化的第一步是只显示需要的数据,即只使用需要的列进行查询SELECTively。

      2. 不需要复制第一列。

      3. 使用方法 DO & FOR 循环本质上很慢。

      4. 简单地说:

            dgv01.RowHeadersVisible = False
            dgv01.SelectAll()
            Clipboard.SetDataObject(dgv01.GetClipboardContent())
            dgv001.ClearSelection()
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-07
        • 2013-04-21
        相关资源
        最近更新 更多