Как указано в комментариях, вы не используете ваше заявление With ws
. Я видел эту проблему в еще одном из ваших вопросов в начале месяца, поэтому я решил дать объяснение, как правильно использовать утверждение.
Рассмотрим этот код:
Sub WithStatementExample()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
Range("A1").Value = "This cell is A1 and this sheet name is " & ws.Name
ActiveSheet.Range("A2").Value = "This cell is A2 and this sheet name is " & ws.Name
End With
End Sub
Теперь, хотя наши операторы инкапсулированы в операторе With
, вывод в ячейки A1
и A2
фактически будет на любом листе активен во время выполнения кода.
В качестве примера рассмотрим эту новую книгу с 3 листами, все с именами по умолчанию:
Если мы выполняем код на основе В книге на этом скриншоте результаты будут go, где мы предполагаем, что они будут - Sheet1
клеток A1
и A2
. Но если мы запускаем код, пока Sheet3
активен, код выводит значения в Sheet3
ячеек A1
и A2
.
Это связано с тем, что в нашем операторе With
мы не использовали наш лист ws
в качестве квалификатора объекта для свойства Range
.
Свойство range может применяться как к Application
, так и к Worksheet
объекты и по документация Application.Range :
При использовании без квалификатора объекта это свойство является ярлыком для ActiveSheet.Range (оно возвращает диапазон из активного лист; если активный лист не является рабочим листом, свойство не выполняется).
Чтобы получить инструкции в блоке With
с использованием объекта , введите .
перед вашими заявлениями:
Sub WithStatementExample()
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
.Range("A1").Value = "This cell is A1 and this sheet name is " & ws.Name
.Range("A2").Value = "This cell is A2 and this sheet name is " & ws.Name
End With
End Sub
Теперь вывод будет только go на лист, присвоенный переменной ws
- в данном случае Sheet1
.
Если вам необходимо применить некоторые утверждения к другим листам но выполненный в вашем блоке With
, вам лучше использовать явную ссылку на книгу, а не ActiveSheet
- Это поможет объяснить больше - (Как избежать использования select в vba)
Так что, если бы ListObjects
в вашем коде было на самом деле Sheets("TOC")
, а не ws
, на которое ссылается l oop, я бы изменил ActiveSheet.ListObjects...
и ActiveSheet.ListObjects("Table1")...
на:
wb.Sheets("TOC").ListObjects...
wb.Sheets("TOC").ListObjects("Table1")...
С вашим For Each...Next
l oop ваша переменная ws
в этом случае представляет объект - в частности, рабочий лист. Переменной ws
присваивается следующий объект на каждой итерации, поэтому вам не нужно независимо присваивать объекту таблицы переменную l oop.
В моем примере выше у меня было 3 листа. Два приведенных ниже кодовых блока достигнут одинакового результата: один через For Each...Next
l oop, а другой без.
For Each ... Следующий подход:
Sub ForEachExample()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Debug.Print ws.Name
Next ws
End Sub
Нет l oop подход:
Sub NoLoopExample()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(1) 'The same as Sheets(1) or Sheets("Sheet1")
Debug.Print ws.Name
Set ws = ThisWorkbook.Sheets(2) 'The same as Worksheets(2) or Sheets("Sheet2")
Debug.Print ws.Name
Set ws = ThisWorkbook.Sheets("Sheet3") 'The same as Worksheets(3) or Sheets(3)
Debug.Print ws.Name
End Sub
Оба они выведут следующее в ближайшее окно в VBE:
Sheet1
Sheet2
Sheet3
В своем обновленном коде вы устанавливаете ws
в ThisWorkbook.Sheets("Sheet2")
.
- Вам понадобится рабочий лист с именем
"Sheet2"
в вашей книге, иначе вы получите ошибку Runtime Error 9: subscript out of range
. - Следующая строка в вашем коде -
For Each...Next
оператор, который установит ws
на первый лист в коллекции Worksheets
, независимо от предыдущей строки кода.
Я отмечаю, что строка кода избыточна в вашей текущей процедуре и, в зависимости от имен ваших таблиц, вероятно, вызовет ошибку во время выполнения.
См. Документацию For Each ... Next .
С вашим оператором Select Case
ваша первая строка Select Case ws.Names
должна выбросить Compile Error: Type mismatch
. ws.Names
возвращает коллекцию заданных c имен листа на основе квалификатора объекта (слева) - в данном случае ws
. Поскольку мы специально ищем имя листа, оно должно быть ws.Name
, которое возвращает имя квалификатора объекта.
Поэтому, чтобы принять это во внимание, это может выглядеть примерно так:
For Each ws In ThisWorkbook.Worksheets
Select Case ws.Name
Case "TOC"
'Do nothing
Case Else
'Do your actions here
End Select
Next ws
В качестве примечания, вы также можете добиться того же с помощью оператора If...Else
, например, так:
For Each ws In ThisWorkbook.Worksheets
If ws.Name = "TOC" Then 'Note by using = "TOC" must match exactly, including letter casing.
'Do nothing
Else
'Do your actions here
End If
Next ws