Как эффективно кодировать для доступа к глобальным именованным диапазонам в VBA - PullRequest
0 голосов
/ 04 января 2019

Я ищу альтернативные, общие методы кодирования для работы с глобальными именованными диапазонами в VBA. Я надеюсь на ответы здесь, с некоторыми новыми обобщенными предложениями и подходами.

Я предлагаю несколько методов, которые я использовал, но эти методы не позволяют избежать всех проблем - мне бы хотелось: простота кодирования и составления электронных таблиц; терпимый к изменениям электронной таблицы, и; простота поиска / ссылки месяцев спустя.

Когда я создаю электронную таблицу, которая позже будет использовать VBA, я создаю именованные диапазоны (обычно глобальные имена) в формулах электронной таблицы. Диапазоны полезны там на листах, и полезны в качестве справки от VBA. Как правило, я не добавляю / не изменяю коллекцию имен в VBA; Я просто ссылаюсь на коллекцию.

При кодировании VBA я получаю доступ к именованным диапазонам, созданным в книге. Если я вырезал / вставил именованные ячейки / диапазоны, отредактировал рабочую книгу и листы, VBA все еще работает.

Тем не менее, глобальные имена, созданные в среде рабочих таблиц, не соответствуют всем трем требованиям в среде VBA, особенно при изменении кода или рабочих таблиц.

В Моем Идеальном Мире:

wb.range("myGlobalRangeName")

Мой идеальный мир надеется, что глобальные ссылки на рабочую книгу, созданные в электронной таблице , являются глобальными , но без пояснений VBA ожидает, что эта ссылка будет в ActiveWorkBook и ActiveWorkSheet.

Мысль первая: Я знаю, что Range("myGlobalRangeName") обращается к этому диапазону, а

Таким образом, я часто использую этот фрагмент

wb.Worksheets("SheetOne").Range("myGlobalRangeName")

может быть построен внутри With блоков, определяя рабочий лист, даже если диапазон является глобальной ссылкой.

Перемещение именованных ячеек на другие листы нарушает эту ссылку (хотя Имя является Глобальным!). Я должен вернуться по всему коду в поисках неуместных ссылок; или я могу выполнить код и надеюсь поймать ошибки ...

Мысль вторая: Вместо этого я могу написать что-то вроде этого, чтобы получить доступ к коллекции имен для рабочей книги:

wb.Names("myGlobalRangeName").RefersToRange

но добавление RefersToRange это ... ну ... раздражает. Он скучает по простоте совершенного мира.

Три мысли: Я создаю отдельный worksheet со всеми значениями, которые я хочу перехватить на других листах, и я создаю диапазоны только на этом отдельном листе. Работают ссылки на ячейки в книге и доступ к ним с помощью VBA. Таким образом, VBA начинается с

Dim wsNames as spreadsheet
set wsNames = wb.worksheets("SheetWithNames")

и ссылки на имена всегда использовали wb.wsNames и выглядели так:

with wb
    .... .wsNames.range("myGlobalRangeName") ....
end with

или другие полезные варианты.

Тем не менее, это тоже может запутаться - мне нужно вернуться назад, чтобы увидеть, где реальные данные, когда я позже исправлю электронную таблицу или VBA. Иногда этот метод работает, особенно если я цепко имя диапазона на этом листе только для потребления VBA, используйте действительно запоминающиеся имена, и помните места, и помню, что я делал все эти месяцы спустя ...

Вывод: Я что-то упустил? Существуют ли другие, возможно более простые, общие методы кодирования, кроме использования

  • RefersToRange с name collection или
  • wb.worksheets("SheetName").Range("myGlobalRange") ссылки, которые явно идентифицируют [текущий] лист, или
  • размещение RangeNames и реферальных формул на отдельном листе с ссылками на диапазоны VBA как wsNames.Range("myGlobalRange").

Я не хочу так много печатать; или создайте переменные процедуры для захвата значений перед их использованием в присваиваниях. Беспорядок становится ... ну ... труднее читать и хуже отследить, присваиваю ли я значение одной ячейки другой в другой книге, и один или оба используют глобальные диапазоны.

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Вы можете сохранить свои диапазоны имен в Enum, а затем обернуть класс вокруг доступа к ним. Было бы немного поработать над настройкой, однако вы могли бы автоматизировать создание этого класса, который будет специфичен для существующей книги с некоторым программированием VBA IDE, если вы хотите.

Я не делал эту часть, но я разделяю подход, который мог бы помочь.

Добавьте это в класс, назовите это NameRangeHelper

'Update these to correspond to the named ranges in your workbook, or
'those range you want access to with this approach
Public Enum NamedRanges
    Example1
    Example2
    Example3
End Enum

Private pNamedRanges As Object

Private Sub Class_Initialize()
    Dim NamedRange  As Name
    Dim NamedRanges As Names

    Set NamedRanges = ThisWorkbook.Names
    Set pNamedRanges = CreateObject("Scripting.Dictionary")

    For Each NamedRange In NamedRanges
        If Not pNamedRanges.Exists(NamedRange.Name) Then
            If TypeName(NamedRange.RefersToRange) = "Range" Then pNamedRanges.Add NamedRange.Name, NamedRange.RefersToRange
        End If
    Next

End Sub

Private Sub Class_Terminate()
    Set pNamedRanges = Nothing
End Sub

Public Function GetRange(RangeName As NamedRanges) As Excel.Range
    Dim RangeStringName As String
    RangeStringName = GetEnumName(RangeName)
    If pNamedRanges.Exists(RangeStringName) Then Set GetRange = pNamedRanges(RangeStringName)
End Function

Private Function GetEnumName(RangeName As NamedRanges) As String
    Select Case RangeName
        Case NamedRanges.Example1
            GetEnumName = "Example1"
        Case NamedRanges.Example2
            GetEnumName = "Example2"
        Case NamedRanges.Example3
            GetEnumName = "Example3"
        Case Else
            GetEnumName = vbNullString
    End Select
End Function

Public Function GetSheetFromRange(RangeName As NamedRanges) As Excel.Worksheet
    Set GetSheetFromRange = GetRange(RangeName).Parent
End Function

Public Function GetWorkbookFromRange(RangeName As NamedRanges) As Excel.Workbook
    Set GetWorkbookFromRange = GetRange(RangeName).Parent.Parent
End Function

Вот код клиента с примером доступа к Range с определенным Enum.

 Sub ExampleNamedRangeHelper()
    Dim rngHelper As NamedRangeHelper: Set rngHelper = New NamedRangeHelper
    Dim rng       As Range
    Set rng = rngHelper.GetRange(Example1)
    Debug.Print rng.Address, rngHelper.GetSheetFromRange(Example1).Name, rngHelper.GetWorkbookFromRange(Example1).Name
End Sub

Используя этот подход, ваши имена находятся в Enum, и вы получаете Intellisense, чтобы упростить выбор / запоминание имен диапазонов.

0 голосов
/ 04 января 2019

Как правило, я получил то, что мне было нужно, с помощью коллекции имен книг, в которой можно хранить формулы и диапазоны. Оба могут быть либо относительно рабочего листа, который является активным, либо абсолютным.

Большая разница между:

Вызовите Thisworkbook.Names.Add (Имя: = "Боб", RefersTo: = Диапазон ("Лист2! $ F $ 19"))

и

Вызовите Thisworkbook.Names.Add (Имя: = "Дуг", RefersTo: = "Лист2! $ F $ 19")

Если эта ячейка F19 на Листе 2 будет перемещена, то Боб будет ссылаться на новое местоположение в любом месте рабочей книги; переместите его на новые листы, Боб будет следовать. Но Даг будет ссылаться на Лист 2, F19, навсегда, несмотря ни на что.

Тогда ссылка будет просто [Bob] или Range («Bob») и будет ссылаться на другую рабочую таблицу, чем активная таблица, если это будет необходимо.

StackExchange отметил связанный с этим вопрос, который был очень интересным:

Excel VBA: именуемая формула / диапазон имен в зависимости от рабочей области, зависимый от рабочей таблицы (результат изменяется в зависимости от активной рабочей таблицы)

... здесь имя уровня рабочей книги может содержать формулу, и формула может иметь одно из значений, одинаковых для всей рабочей книги, или относиться к локальному значению на листе. И действительно, вы можете смешать два в одной формуле.

...