Могу ли я использовать функцию VBA для возврата (динамического) списка допустимых значений в проверку данных Excel? - PullRequest
5 голосов
/ 24 января 2011

Для данной ячейки я выбираю Данные / Проверка и устанавливаю Разрешить в «Список». Теперь я хочу установить Source следующим образом:

= rNames (Regs)

но это не работает (имя не найдено). Поэтому я иду Вставить / Имя / Определить и создать "REGNAMES", просто назначив формулу выше (без диапазона ячеек). Затем я возвращаюсь к данным / проверке, и когда я устанавливаю источник следующим образом:

= REGNAMES

Теперь я получаю «Источник в настоящее время оценивается как ошибка». К сожалению, эта ошибка не исчезает даже после того, как я ее игнорирую. Я могу создать формулу диапазона на листе так:

{= REGNAMES}

и перетащите его вправо через пару ячеек, и функция rNames точно вернет

Вариант № 1 | Варианты № 2 | ...

То есть функция возвращает диапазон, как и предполагалось.

Я знаю, что могу использовать макрос-код для управления настройками List для этой ячейки вне VBA. Мне не очень нравятся эти побочные эффекты. Я бы предпочел чистое дерево зависимостей, построенное на функциях. Любые идеи, как получить данные / проверки для принятия значений массива, возвращенных из rNames?

Спасибо.

PS: rNames возвращает диапазон результатов в качестве варианта, если он имеет какое-либо отношение.

Ответы [ 5 ]

8 голосов
/ 25 января 2011

Мне кажется, проблема в том, что диалог проверки данных принимает только следующие «списки»:

  • фактический список вещей, введенный непосредственно в поле «Источник»

  • буквенная ссылка диапазона (например, $ Q $ 42: $ Q $ 50)

  • именованная формула, которая сама по себе разрешается в ссылку на диапазон

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

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

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

Public Function validationList(someArg, someOtherArg)

    'Pretend this got calculated somehow based on the above args...
    validationList = Array("a", "b", "c")
End Function

И вы назвали ее из $ Q $ 42: $ Q $ 50 в качестве формулы массива.Вы получите три ячейки с «a», «b» и «c» в них, а остальные ячейки будут иметь ошибки # N / A, потому что возвращаемый массив будет меньше, чем диапазон, который называется UDF.Пока все хорошо.

Теперь, есть еще одна UBA VBA, которая возвращает только "занятую" часть диапазона, игнорируя ячейки с ошибками # N / A:

Public Function extractSeq(rng As Range)

    'On Error GoTo EH stuff omitted...

    'Also omitting validation - is range only one row or column, etc.

    Dim posLast As Long
    For posLast = rng.Count To 1 Step -1
        If Not IsError(rng(posLast)) Then
            Exit For
        End If

        If rng(posLast) <> CVErr(xlErrNA) Then
            Exit For
        End If
    Next posLast

    If posLast < 1 Then
        extractSeq = CVErr(xlErrRef)
    Else
        Set extractSeq = Range(rng(1), rng(posLast))
    End If
End Function

Вы можете затемвызовите это из именованной формулы, например, так:

=extractSeq($Q$42:$Q$50)

и именованная формула вернет ссылку на диапазон, в которой Excel примет допустимый список проверки.Неуклюжий, но без побочных эффектов!

Обратите внимание на использование ключевого слова «Set» в приведенном выше коде.Это не ясно из вашего вопроса, но это может быть единственной частью всего этого ответа, который имеет значение для вас.Если вы не используете «Set» при попытке вернуть ссылку на диапазон, VBA вместо этого вернет значение диапазона, которое нельзя использовать в качестве списка проверки.

3 голосов
/ 28 сентября 2011

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

Любой диапазон, к которому может быть применено правило проверки, может иметьэто правило применяется программно.Таким образом, если вы хотите применить правило к ячейке A1, вы можете сделать это:

ActiveSheet.Range("A1").Validation.Add xlValidateList, , , "use, this, list"

Выше добавлена ​​проверка раскрывающегося списка в ячейке, которая содержит элементы «use», «this» и «список."Если вы переопределяете событие Worksheet_SelectionChange() и проверяете наличие определенных диапазонов в нем, вы можете вызвать любое количество подпрограмм для создания / удаления правил проверки.Прелесть этого метода в том, что упомянутый список может быть любым списком, который может быть создан в VBA.Мне нужен был динамически генерируемый список постоянно меняющихся подмножеств рабочих листов в рабочей книге, которые я затем объединял вместе, чтобы создать список проверки.

В событии Worksheet_SelectionChange() я проверяю диапазон, а затем, если он совпадает, запускаю подпрограмму правила проверки, таким образом:

Private Sub Worksheet_SelectionChange(ByVal Target as Range)

    If Target.Address = "$A$1" Then
        UpdateValidation
    End If

End Sub

Код построителя списка проверки в UpdateValidation() делает это:

Public Sub UpdateValidation()

    Dim sList as String
    Dim oSheet as Worksheet

    For Each oSheet in Worksheets
        sList = sList & oSheet.Name & ","
    Next

    sList = left(sList, len(sList) -1)  ' Trim off the trailing comma

    ActiveSheet.Range("A1").Validation.Delete
    ActiveSheet.Range("A1").Validation.Add xlValidateList, , , sList

End Sub

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

0 голосов
/ 23 июля 2015

На будущее:

Затем используется именованный диапазон, а именованный диапазон устанавливается как значение «Проверка данных» «Список»

Function uniqueList(R_NonUnique As Range) As Variant

    Dim R_TempList As Range
    Dim V_Iterator As Variant
    Dim C_UniqueItems As New Collection

    On Error Resume Next
    For Each V_Iterator In R_NonUnique
        C_UniqueItems.Add "'" & V_Iterator.Parent.Name & "'!" & V_Iterator.Address, CStr(V_Iterator.Value2)
    Next V_Iterator
    On Error GoTo 0

    For Each V_Iterator In C_UniqueItems
        If R_TempList Is Nothing Then
            Set R_TempList = Range(V_Iterator)
        End If
        Set R_TempList = Union(R_TempList, Range(V_Iterator))
    Next V_Iterator

    Set uniqueList = R_TempList

End Function
0 голосов
/ 01 февраля 2011

Не лучше ли использовать имена динамического диапазона ?Это довольно просто и не требует никакой VBA.

0 голосов
/ 24 января 2011

Похоже, ваша функция rNames, вероятно, возвращает одномерный массив (который будет рассматриваться как строка).
Попробуйте заставить вашу функцию возвращать столбец в виде двумерного массива на основе 1 (Ansa (1,1), затем Ansa (2,1) и т. Д.)

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