Почему при обращении к отбору динамического списка возникает ошибка «Индекс находится за границами массива»?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При обновлении платформы 1С:Предприятие или снятии режима совместимости разработчики часто сталкиваются с ошибкой «Индекс находится за границами массива» при попытке обратиться к первому элементу отбора динамического списка: Список.Отбор.Элементы[0]. Разберем подробно, почему ранее работавший код перестает функционировать и как правильно управлять отборами динамического списка на современных версиях платформы.

Проанализируем типовой фрагмент кода, вызывающий исключение:


Если ЗначениеЗаполнено(Владелец) Тогда
    Список.Отбор.Элементы[0].ПравоеЗначение = Владелец;
    Список.Отбор.Элементы[0].Использование  = Истина;
Иначе
    Список.Отбор.Элементы[0].Использование  = Ложь;
КонецЕсли;

Выясним причину изменения поведения платформы

В старых версиях платформы (или при включенном режиме совместимости с версией 8.2) отборы, настроенные в конфигураторе, напрямую проецировались в свойство Список.Отбор. В современных версиях 1С:Предприятия 8.3 при снятом режиме совместимости архитектура динамического списка и системы компоновки данных разграничивает слои настроек:

  1. Фиксированные настройки (КомпоновщикНастроек.ФиксированныеНастройки): именно к ним обращается свойство Список.Отбор. По умолчанию эта коллекция пуста, если в нее ничего не добавлялось программно, поэтому обращение по индексу [0] вызывает ошибку.
  2. Пользовательские настройки (КомпоновщикНастроек.ПользовательскиеНастройки): содержат элементы, которые пользователь может интерактивно менять на форме. Эти настройки имеют более высокий приоритет над базовыми настройками и могут перекрывать их.
  3. Базовые настройки (КомпоновщикНастроек.Настройки): именно здесь сохраняются отборы, заданные разработчиком в свойствах динамического списка в конфигураторе.

Таким образом, обращение к Список.Отбор.Элементы[0] падает из-за того, что фиксированные настройки не содержат элементов, настроенных в конфигураторе. Кроме того, прямое обращение по жесткому индексу [0] является грубой ошибкой проектирования, так как порядок элементов в коллекции может измениться.

Рассмотрим правильные и надежные способы программной установки отбора.

Способ 1. Использование функции БСП (рекомендуемый вариант)

Если в конфигурации используется «Библиотека стандартных подсистем» (БСП), наиболее правильным решением будет вызов готовой экспортной процедуры. Она самостоятельно выполняет поиск нужного поля, добавляет элемент при его отсутствии и корректно применяет изменения:


ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
    Список,
    "Владелец",
    Владелец,
    ВидСравненияКомпоновкиДанных.Равно,
    "Отбор по владельцу",
    ЗначениеЗаполнено(Владелец)
);

Этот метод избавляет от необходимости писать ручные поиски по коллекциям компоновщика настроек и защищает код от ошибок при изменении структуры отборов.

Способ 2. Программное добавление и поиск в фиксированных настройках

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


ПолеОтбора = Новый ПолеКомпоновкиДанных("Владелец");
ЭлементОтбора = Неопределено;

// Выполняем поиск существующего элемента отбора
Для Каждого Элемент Из Список.Отбор.Элементы Цикл
    Если Элемент.ЛевоеЗначение = ПолеОтбора Тогда
        ЭлементОтбора = Элемент;
        Прервать;
    КонецЕсли;
КонецЦикла;

// Если элемент не найден — создаем его
Если ЭлементОтбора = Неопределено Тогда
    ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементОтбора.ЛевоеЗначение = ПолеОтбора;
    ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
КонецЕсли;

// Задаем значение и активность отбора
Если ЗначениеЗаполнено(Владелец) Тогда
    ЭлементОтбора.ПравоеЗначение = Владелец;
    ЭлементОтбора.Использование  = Истина;
Иначе
    ЭлементОтбора.Использование  = Ложь;
КонецЕсли;

Способ 3. Управление отбором через КомпоновщикНастроек

Если отбор был изначально создан в конфигураторе в составе базовых настроек, доступ к нему осуществляется через КомпоновщикНастроек.Настройки.Отбор. Разберем по шагам, как правильно работать с этим слоем:

  1. Находим нужный элемент в коллекции базовых настроек по его левому значению.
  2. Проверяем, включен ли данный отбор в пользовательские настройки (заполнено ли свойство ИдентификаторПользовательскойНастройки).
  3. Если идентификатор присутствует, меняем состояние элемента в коллекции Список.КомпоновщикНастроек.ПользовательскиеНастройки, иначе пользовательские настройки перекроют значение базовых.

Посмотрим на пример реализации:


ПолеОтбора = Новый ПолеКомпоновкиДанных("Владелец");
ЭлементБазовый = Неопределено;

Для Каждого Элемент Из Список.КомпоновщикНастроек.Настройки.Отбор.Элементы Цикл
    Если Элемент.ЛевоеЗначение = ПолеОтбора Тогда
        ЭлементБазовый = Элемент;
        Прервать;
    КонецЕсли;
КонецЦикла;

Если ЭлементБазовый <> Неопределено Тогда
    Если Не ПустаяСтрока(ЭлементБазовый.ИдентификаторПользовательскойНастройки) Тогда
        // Находим элемент в пользовательских настройках
        ЭлементПользовательский = Список.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Найти(
            ЭлементБазовый.ИдентификаторПользовательскойНастройки
        );
        Если ЭлементПользовательский <> Неопределено Тогда
            ЭлементПользовательский.ПравоеЗначение = Владелец;
            ЭлементПользовательский.Использование  = ЗначениеЗаполнено(Владелец);
        КонецЕсли;
    Иначе
        // Меняем в базовых настройках, если элемент не выведен пользователю
        ЭлементБазовый.ПравоеЗначение = Владелец;
        ЭлементБазовый.Использование  = ЗначениеЗаполнено(Владелец);
    КонецЕсли;
КонецЕсли;

Способ 4. Использование параметров динамического списка

Если требуется жесткий отбор (например, отображение данных конкретного владельца), зачастую эффективнее использовать не отбор компоновки, а параметр в тексте запроса динамического списка. Для этого в тексте запроса списка указываем условие ГДЕ Владелец = &Владелец и устанавливаем параметр программно:

Список.Параметры.УстановитьЗначениеПараметра("Владелец", Владелец);

Такой подход полностью исключает конфликты пользовательских и программных настроек и обеспечивает оптимальное построение запроса к СУБД.

← На главную