Почему оператор VBA TypeOf не работает
Я уже несколько дней борюсь с проблемой Excel 2007. Ниже приведен список всех фактов, которые, как я могу думать, могут иметь значение:
-
IDetailSheet - это класс, объявленный в проекте VBA несколькими способами, и который вызывает ошибку в его инициализаторе класса, так что он не может быть создан (делая его абстрактным).
-
Параметр Explicit устанавливается во всех модулях.
-
Десять рабочих листов проекта VBA реализуют IDetailSheet и компилируются (как и весь проект).
-
CDetailSheets - это класс, объявленный в проекте VBA, который обертывает объект Collection и предоставляет объект Collection в виде коллекции IDetailSheet. Он также предоставляет некоторые дополнительные методы для выполнения определенных методов IDetailSheet для всех сборщиков.
-
В своем инициализаторе класса (вызванном из обработчика события Workbook_ Open и назначаемом глобальной переменной), CDetailSheet выполняет следующий код для заполнения частной коллекции DetailSheets:
Dim sht as EXCEL.WorkSheet
For Each sht in ActiveWorkbook.Worksheets
If TypeOf sht is IDetailSheet Then
Dim DetailSheet as IDetailSheet
Set DetailSheet = sht
DetailSheets.Add DetailSheet, DetailSheet.Name
End If
Next sht
-
В некоторых обратных вызовах ленты выполняется следующий код:
If TypeOf ActiveWorkbook.ActiveSheet is IDetailSheet Then
Dim DetailSheet as IDetailSheet
Set DetailSheet = ActiveWorkbook.ActiveSheet
DetailSheet.Refresh *[correction]*
End If
-
Все элементы ActiveX были удалены из рабочей книги, после того как были идентифицированы с другими проблемами стабильности (первоначально было несколько десятков). Для замены функций, первоначально связанных с элементами управления ActiveX, была создана свободная интерфейсная лента.
-
Существует надстройка Hyperion от корпоративного шаблона, но она не используется в этой книге.
Когда все сказано и сделано, появляется следующий симптом, когда рабочая книга запущена:
- Любое количество экземпляров IDetailSheet распознается в Инициализаторе CDetailSheets по TypeOf Is, от 1 (наиболее часто встречающегося) до иногда 2 или 3. Никогда не ноль, не более 3, и, конечно же, никогда не доступны 10 доступных. (Не всегда один и тот же, хотя и находится рядом с передним рядом с набором, по-видимому, увеличивает вероятность признания.)
- Каковы бы ни были экземпляры реализации IDetailSheet в инициализаторе CDetailSheets (и как только я могу определить, только такие экземпляры) также распознаются с помощью TypeOf... Является ли обратная связь ленты.
Может кто-нибудь объяснить, почему большая часть TypeOf... Не работает ли операция? Или как решить проблему?
Я прибегал к ручному созданию v-таблиц (т.е. Больших уродливых операторов Select Case... End Select), чтобы заставить работать функциональность, но на самом деле мне кажется довольно неловко иметь мое имя рядом с таким кодом. Кроме того, я вижу, что это будущий кошмар.
Думая, что это могут быть устаревшие проблемы с p-кодом, я пошел до степени удаления файла Project.Bin из расширенного zip файла XLSM, а затем вручную импортировал весь код VBA. Без изменений. Я также попытался добавить имя проекта ко всем обычаям IDetailSheet, чтобы сделать их miFab.IDetailSheet, но опять же безрезультатно. (miFab - название проекта.)
Ответы
Ответ 1
Есть несколько способов обмануть, используя CallByName. Вам придется обойти эту ошибку так или иначе.
Быстрый грязный пример
Каждый лист, начинающийся с строки реализации, должен иметь общедоступную функцию GetType.
Я подключил субтитры TestSheet к кнопке на моей ленте. Он помещает возвращаемое имя типа в ячейку A1, чтобы продемонстрировать функцию.
Module1
'--- Start Module1 ---
Option Explicit
Public Sub TestSheet()
Dim obj As Object
Set obj = ActiveSheet
ActiveSheet.[A1] = GetType(obj)
End Sub
Public Function GetType(obj As Object) As String
Dim returnValue As String
returnValue = TypeName(obj)
On Error Resume Next
returnValue = CallByName(obj, "GetType", VbMethod)
Err.Clear
On Error GoTo 0
GetType = returnValue
End Function
'--- End Module1 ---
Лист1
'--- Start Sheet1 ---
Implements Class1
Option Explicit
Public Function Class1_TestFunction()
End Function
Public Function GetType() As String
GetType = "Class1"
End Function
'--- End Sheet1 ---
Ответ 2
Я нашел этот вопрос после публикации моей собственной аналогичной проблемы, поскольку TypeOf не работает с ActiveSheet рабочей книги Excel, который реализует интерфейс
У меня нет окончательного объяснения, но я думаю, что у меня есть обходное решение.
Я подозреваю, что это потому, что [код] реализует интерфейс на Sheet1 или Chart и расширяет Sheet1/Chart1, но Sheet1 уже расширяет рабочий лист (а Chart1 уже расширяет диаграмму).
В моем тестировании я могу заставить VBA вернуть реальное значение TypeOf
, сначала получив доступ к свойству листа. Это означает, что вы делаете что-то некрасивое, как:
'Explicitly access ThisWorkbook.ActiveSheet.Name before using TypeOf
If TypeOf ThisWorkbook.Sheets(ThisWorkbook.ActiveSheet.Name) Is PublicInterface Then
Ответ 3
Если вы не доверяете TypeOf
, плуг и игнорируйте ошибки:
Dim sht as EXCEL.WorkSheet
For Each sht in ActiveWorkbook.Worksheets
'If TypeOf sht is IDetailSheet Then
Dim DetailSheet As IDetailSheet
On Error Resume Next
Set DetailSheet = sht
On Error GoTo 0
If Not DetailSheet Is Nothing Then
DetailSheets.Add DetailSheet, DetailSheet.Name
End If
Next sht
Если это не сработает, рабочие листы действительно не будут IDetailSheet
в это время по крайней мере.