在一次调用中从Excel中检索多个单元格属性?

时间:2016-09-01 07:17:13

标签: c# excel ms-office com-interop

我需要检索几千个单元格的背景属性(Range.Interior.Color)。由于COM-Interop限制,单独循环每个单元格非常慢。

是否可以从一次调用中包含多个单元格的.Text中检索不是.Value.Value2Range的单元格属性?

2 个答案:

答案 0 :(得分:0)

你可以做到这一点,但这不是微不足道的,所以我不确定它是否值得尝试模仿类似行为的麻烦。

基本上你需要在Excel中创建一个为你工作的宏,然后在宏完成后简单地恢复结果。这基本上模仿了Value的行为。我不确定为什么MS决定不在Range中实现所有属性以表现出相同的方式,这很奇怪。

为此,您需要引用Microsoft Visual Basic for Application Extensibility 5.3 COM库。这为您提供了动态构建宏并将其添加到Excel工作簿所需的工具。

第一步是创建一个方法,将一个模块和所需的宏添加到您正在与之交互的工作簿中(如果您在不同的工作表上使用该函数,还可以打开一个空白工作簿并在那里创建宏)开幕式和闭幕式。)

以下示例添加一个宏,该宏返回一个包含指定范围内所有单元格颜色的数组。这是用VBA编写的,我没有VS和我一起但是C#版本应该非常简单易用。

Sub AddCode()
   Dim wb As Workbook
   Dim xPro As VBIDE.VBProject
   Dim xCom As VBIDE.VBComponent
   Dim xMod As VBIDE.CodeModule

   Set wb = ActiveWorkbook

   With wb
       Set xPro = .VBProject
       Set xCom = xPro.VBComponents.Add(vbext_ct_StdModule)
       Set xMod = xCom.CodeModule

       With xMod
           .AddFromString "Public Function GetInteriorColors(r As Range) As Variant" & vbCrLf & _
                          "    Dim colors() As Long" & vbCrLf & _
                          "    Dim row As Integer" & vbCrLf & _
                          "    Dim column As Integer" & vbCrLf & _
                          "    ReDim colors(r.Rows.Count - 1, r.Columns.Count - 1)" & vbCrLf & _
                          "    For row = 1 To r.Rows.Count" & vbCrLf & _
                          "        For column = 1 To r.Columns.Count" & vbCrLf & _
                          "            colors(row - 1, column - 1) = r.Cells(row, column).Interior.Color" & vbCrLf & _
                          "        Next" & vbCrLf & _
                          "    Next" & vbCrLf & _
                          "    GetInteriorColors = colors" & vbCrLf & _
                          "End Function"
       End With
   End With
End Sub

需要注意的事项;我执行AddFromString时有时会遇到奇怪的错误。宏代码正确添加到模块但我有时会收到错误;吞咽它似乎并不有害但如果你有同样的问题,我会调查它。

现在,一旦你有了宏,带回结果很容易(再次,用VBA写的):

Public Function GetColors(r As Range) As Long()
    //Note the absolute path to the macro; this is probably needed if the macro is in a different workbook.
    GetColors = Application.Run(ActiveWorkbook.Name & "!GetInteriorColors", r)
End Function

答案 1 :(得分:0)

我会尝试以下内容(用VBA编写,但可以转换为C#):

Public Sub GetColors()
    Dim ewsTarget As Worksheet: Set ewsTarget = ActiveWorkbook.Worksheets(1)
    ewsTarget.Copy , ewsTarget.Parent.Worksheets(ewsTarget.Parent.Worksheets.Count)
    Dim ewsCopy As Worksheet: Set ewsCopy = ewsTarget.Parent.Worksheets(ewsTarget.Parent.Worksheets.Count)
    ewsCopy.UsedRange.ClearContents
    ewsCopy.UsedRange.Columns.EntireColumn.ColumnWidth = 0.5
    ewsCopy.UsedRange.Rows.EntireRow.RowHeight = 5#
    ewsCopy.UsedRange.CopyPicture xlScreen, xlBitmap
    ewsCopy.Delete
End Sub

此代码在剪贴板上放置一个位图。此位图是从工作表的副本创建的,但是,单元格内容将被删除,因此您将只看到单元格的背景,此外行和列具有相同的高度和长度。然后,您的C#程序可以获取此位图并获取单个像素,因为行和列具有相同的高度和宽度,因此可以轻松计算单元格的位置。

我知道这只是一种解决方法,但我认为没有更好的解决方案。它只是一种方式(不能写,只读),很难扩展到其他属性(可能是边框和字体颜色)。