VB Excel(VSTO)-将数据​​表导出为具有基于数据类型的列格式的Excel

时间:2019-11-13 14:43:41

标签: excel vb.net vsto

我已经在VB中继承了一个项目,这是我不熟悉的语言。该项目是一个自定义Excel功能区,可从存储过程中导出数据。

问题是当前方法要求将DataTable的所有值都转换为字符串,并以类似的方式导出为CSV。虽然这是导出数据的最简单,最快的方法,但是最终用户必须在填充数据后手动将所有非字符串列转换为正确的格式。我正在尝试一种方法,以便根据数据类型对导出数据的每一列进行格式化。

当前方法/原始代码:

Public Sub PopulateExcel(QueryTable As Data.DataTable, SheetName As String)
    Dim wsActive As Excel.Worksheet
    wsActive = Globals.ThisAddIn.Application.ActiveWorkbook.Worksheets.Add()

    Dim wb As Excel.Workbook
    wb = Globals.ThisAddIn.Application.ActiveWorkbook

    Dim intName As Integer = 1
    For Each Cell As DataColumn In QueryTable.Columns
        wsActive.Cells(3, intName) = Cell.ColumnName
        wsActive.Cells(3, intName).Font.Bold = True
        wsActive.Cells(3, intName).Interior.Color = RGB(217, 225, 242)
        intName += 1
    Next

    Dim intRow As Integer = 0
    Dim strData As String(,) = New String(QueryTable.Rows.Count - 1, QueryTable.Columns.Count - 1) {}
    For Each row As DataRow In QueryTable.Rows
        Dim intColumn As Integer = 0
        For Each Cell As DataColumn In QueryTable.Columns
            strData(intRow, intColumn) = row(Cell).ToString()
            intColumn += 1
        Next
        intRow += 1
    Next

    wsActive.Range(wsActive.Cells(4, 1), wsActive.Cells(QueryTable.Rows.Count + 1, QueryTable.Columns.Count)).Value = strData
    wsActive.Columns.AutoFit()
    wsActive.Rows.AutoFit()

我很不高兴地尝试了两种解决方案:

1)在没有字符串转换的情况下在 QueryTable 循环中执行导出。

此方法有效,但对性能有相当大的影响,因为它一次分配一个单元格值。

    Dim intRow As Integer = 4
    For Each row As DataRow In QueryTable.Rows
        Dim intColumn As Integer = 1
        For Each Cell As DataColumn In QueryTable.Columns
            wsActive.Cells(intRow, intColumn) = row(Cell)
            intColumn += 1
        Next
        intRow += 1
    Next

    wsActive.Columns.AutoFit()
    wsActive.Rows.AutoFit()

2)导出数据后,根据列名更改列格式。我对此没有任何运气。

在下面的示例中,我尝试首先导出数据,并在创建列名称时尝试查找名称中带有“ Qty”的任何列,并将列格式转换为数字格式。

    Dim intRow As Integer = 0
    Dim strData As String(,) = New String(QueryTable.Rows.Count - 1, QueryTable.Columns.Count - 1) {}
    For Each row As DataRow In QueryTable.Rows
        Dim intColumn As Integer = 0
        For Each Cell As DataColumn In QueryTable.Columns
            strData(intRow, intColumn) = row(Cell).ToString()
            intColumn += 1
        Next
        intRow += 1
    Next

    wsActive.Range(wsActive.Cells(4, 1), wsActive.Cells(QueryTable.Rows.Count + 1, QueryTable.Columns.Count)).Value = strData
    wsActive.Columns.AutoFit()
    wsActive.Rows.AutoFit()

    Dim intName As Integer = 1
    For Each Cell As DataColumn In QueryTable.Columns
        wsActive.Cells(3, intName) = Cell.ColumnName
        If Cell.ColumnName.Contains("Qty") Then
           wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count, intName)).NumberFormat = "$#,##0.00_);[Red]($#,##0.00)"
        End If
        wsActive.Cells(3, intName).Font.Bold = True
        wsActive.Cells(3, intName).Interior.Color = RGB(217, 225, 242)
        intName += 1
    Next

我觉得必须有一个更好的方法来解决此问题。任何帮助或建议都很好。

非常感谢。

1 个答案:

答案 0 :(得分:0)

我坚持使用选项2。在将列名添加到工作表时,列格式由列名决定。仍然不要以为这是最好的方法,但是它现在可以使用。

        Dim intName As Integer = 1
    For Each Cell As DataColumn In QueryTable.Columns
        wsActive.Cells(3, intName) = Cell.ColumnName
        If Cell.ColumnName.Contains("Qty") Then
            wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).NumberFormat = "General"
            wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).Value = wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).Value
        End If
        If Cell.ColumnName.Contains("Value") Then
            wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).NumberFormat = "#,##0.00"
            wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).Value = wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).Value
        End If
        If Cell.ColumnName.Contains("Rate") Then
            wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).NumberFormat = "#,##0.0000"
            wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).Value = wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).Value
        End If
        If Cell.ColumnName.Contains("Percentage") Then
            wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).NumberFormat = "#,##0.0000"
            wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).Value = wsActive.Range(wsActive.Cells(4, intName), wsActive.Cells(QueryTable.Rows.Count + 1, intName)).Value
        End If
        wsActive.Cells(3, intName).Font.Bold = True
        wsActive.Cells(3, intName).Interior.Color = RGB(217, 225, 242)
        intName += 1
    Next

    wsActive.Columns.AutoFit()
    wsActive.Rows.AutoFit()