Excel VBA - использовать именованный диапазон в качестве параметра в функции VBA - PullRequest
0 голосов
/ 24 февраля 2019

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

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

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

В этой конкретной строке:

Set FullRange = NamedRange

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

Любая помощь будет высоко ценится!

Идея состоит в том, чтобыобъявить именованный диапазон в качестве параметра.В свою очередь, функция находит этот именованный диапазон и создает новый диапазон из его части (см. SpecificRange).Наконец, он выполняет определенные вычисления с данными из этого нового диапазона.Все это отлично работает, но только в одном листе ... Вот код:

Function myResult(NamedRange As Range, Vessel As String, FromDate As Date, ToDate As Date)

'declare variables in addition to the function parameters declared above
Dim SpecificRange As Range
Dim FullRange As Range
Dim Result As Double
Dim i As Byte

'find the row within the declared "NamedRange" range which contains information for the declared "Vessel"
Set FullRange = NamedRange
Set SpecificRange = Range(FullRange.Find(Vessel, , xlValues, xlWhole).Address, FullRange.Find(Vessel, , xlValues, xlWhole).Offset(0, FullRange.Columns.Count - 1).Address)

i = 1
Result = 0

For i = 1 To FullRange.Columns.Count - 2
    If FullRange(2, i) = "Date" Then
        With WorksheetFunction
            Result = Result + .Max(0, .Min(ToDate, SpecificRange(1, i + 2).Value) - .Max(FromDate, SpecificRange(1, i).Value)) * SpecificRange(1, i + 1).Value
        End With
    End If
Next

myResult = Result

End Function

Большое спасибо!

+++++

Добавитьнекоторые дополнительные сведения, обратите внимание, что при вводе в лист, отличный от того, где находится NamedRange, функция возвращает ноль (0,00), а не ошибку.

Кроме того, когда у меня точно такая же функция (а)на листе, где расположен NamedRange (скажем, «Sheet1») и (b) на другом листе (скажем, «Sheet2»), тогда, когда я запускаю функцию в Sheet1, функция в Sheet2 обновляется правильно!Но когда я запускаю функцию непосредственно в Sheet2, она возвращает ноль ...

Кажется, что он не может найти NamedRange, когда соответствующий лист не активен ...

Вот скриншот:https://i.stack.imgur.com/RpHf3.png

Именованный диапазон вводится пользователем в качестве параметра в функции (см. Первый параметр). Второй параметр в функции (т. Е. Vessel as String) относится к первому столбцу, показанному на скриншоте..

Поэтому, когда пользователь вводит формулу, функция находит NamedRange, а затем создает другой диапазон (т. Е. SpecificRange), который, по сути, является строкой, в которой был найден второй параметр (Критерии 4 на снимке экрана примера).

Тогда это всего лишь расчеты, основанные на оставшихся двух параметрах, но это не имеет отношения к этой проблеме.

1 Ответ

0 голосов
/ 24 февраля 2019

Вы успешно собираете именованный диапазон, ваша проблема в том, что позже в вашем коде вы устанавливаете диапазон на основе адреса, но не указываете лист.Другими словами, ваш код смотрит на ActiveSheet.Range(.ADDRESS).

Вы можете фактически собрать лист из переменной диапазона, вот пример: Set WS = ThisWorkbook.Sheets(NamedRange.Parent.Name)

ОБНОВЛЕНО v3 с помощьюеще несколько комментариев (PGC:)

Function myResult(NamedRange As Range, Vessel As String, FromDate As Date, ToDate As Date)

'declare variables in addition to the function parameters declared above
Dim SpecificRange As Range
Dim FullRange As Range 'PGC: not sure you need this
Dim Result As Double
Dim i As Long 'PGC: use long instead of byte https://stackoverflow.com/questions/26409117/why-use-integer-instead-of-long/51689021#51689021
Dim WS As Worksheet 'PGC: this will be used to narrow your approach.


'find the row within the declared "NamedRange" range which contains information for the declared "Vessel"
Set FullRange = NamedRange 'I don't think you need to change this variable. Using NamedRange should work if you use below.

'PGC: set the WS to be the parent of the range you're working with:
Set WS = ThisWorkbook.Sheets(NamedRange.Parent.Name)

'PGC: since you're using the address text to set the range (probably not ideal), you'll need to specify which WS this Range is on.
Set SpecificRange = WS.Range(FullRange.Find(Vessel, , xlValues, xlWhole).Address, FullRange.Find(Vessel, , xlValues, xlWhole).Offset(0, FullRange.Columns.Count - 1).Address)

'PGC: alternative untested approach that avoids using the address property that is probably best method:
'Set SpecificRange = Range(FullRange.Find(Vessel, , xlValues, xlWhole), FullRange.Find(Vessel, , xlValues, xlWhole).Offset(0, FullRange.Columns.Count - 1))


i = 1
Result = 0

For i = 1 To FullRange.Columns.Count - 2
    If FullRange(2, i) = "Date" Then
        With WorksheetFunction
            Result = Result + .Max(0, .Min(ToDate, SpecificRange(1, i + 2).Value) - .Max(FromDate, SpecificRange(1, i).Value)) * SpecificRange(1, i + 1).Value
        End With
    End If
Next

myResult = Result

End Function
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...