Вы можете сделать это, но это не тривиально, поэтому я не уверен, стоит ли пытаться подражать подобному поведению.
В принципе вам нужно создать макрос в Excel, который выполняет эту работу за вас, а затем просто вернуть результаты после завершения макроса. Это в основном эмулирует поведение Value
. Я не совсем уверен, почему MS решила не реализовывать все свойства в Range
, чтобы вести себя одинаково, странно.
Для этого вам необходимо обратиться к библиотеке COM Microsoft Visual Basic for Application Extensibility 5.3
. Это дает вам необходимые инструменты для динамической сборки и добавления макросов в книгу 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
Я просто попробовал это с 30k-ячейками в VBA, и это заняло меньше секунды. Является ли ваш COM-выход из процесса случайным? Я не могу думать о других свойствах Range, которые, к сожалению, возвращают массив. Я кратко подумал об использовании Excel4, но вам все равно нужно вызвать код vba для вызова функции (скажем) GET.CELL, и они не возвращают массивы в любом случае, так что это не слишком многообещающе. – GodLovesATrier