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

· 9 мин

Содержание

Значение параметра динамического списка устанавливают одной строкой: Список.Параметры.УстановитьЗначениеПараметра("Склад", Склад);. Вызов ставят в обработчик формы ПриСозданииНаСервере, а при смене значения пользователем — в обработчик ПриИзменении реквизита. Сам параметр должен быть в тексте запроса списка в виде &Склад, поэтому у списка включают флажок «Произвольный запрос».

Типичная ситуация: программист делает форму остатков, где сверху поле «Склад», а снизу список товаров. В Конфигураторе всё собирается за пять минут, а при открытии формы появляется ошибка про не установленное значение параметра. Или ошибки нет, но список пустой, хотя данные в базе есть. Почти всегда причина в том, где и как задано значение.

Что такое параметр динамического списка и откуда он берётся

Динамический список работает на механизме компоновки данных. Его запрос — это не обычный Запрос, а схема, которую платформа достраивает сама: добавляет отборы, сортировку, порции чтения. Параметр — именованное значение, которое подставляется в текст запроса вместо &ИмяПараметра.

Параметры появляются только в одном случае: когда у списка задан произвольный запрос и в его тексте есть хотя бы один &. У списка, построенного просто по основной таблице (например, Справочник.Номенклатура без своего запроса), коллекция параметров пустая.

Чем параметр отличается от отбора:

  • 🔹 параметр — часть текста запроса; без значения запрос не выполнится;
  • 🔹 отбор — условие, которое компоновка добавляет поверх запроса; его можно включать и выключать;
  • 🔹 параметр виртуальной таблицы — частный случай параметра: период остатков, условие внутри Остатки(...), Обороты(...), СрезПоследних(...).

Отсюда простое правило. Если условие обязательно и без него список не имеет смысла (дата остатков, текущий пользователь) — это параметр. Если условие необязательное и пользователь может его снять — это отбор.

Как задать значение параметра: конструктор и программный код

Подготовка списка в Конфигураторе

  1. Откройте форму в Конфигураторе и добавьте реквизит формы с типом ДинамическийСписок.
  2. Откройте свойства реквизита (двойной щелчок по нему) и установите флажок «Произвольный запрос».
  3. Напишите текст запроса или откройте конструктор запроса. Параметры записывайте через &.
  4. Укажите «Основную таблицу» — ту, ссылки которой выводит список. Это важно для производительности и для работы команд «Создать», «Изменить».
  5. Перетащите реквизит на форму, чтобы появилась таблица.

Пример запроса:

ВЫБРАТЬ
    Номенклатура.Ссылка КАК Ссылка,
    Номенклатура.Наименование КАК Наименование,
    Номенклатура.Артикул КАК Артикул
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    Номенклатура.Родитель = &Группа

Установка значения при открытии формы

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    Группа = Параметры.Группа; // реквизит формы, пришёл при открытии
    Список.Параметры.УстановитьЗначениеПараметра("Группа", Группа);
    
КонецПроцедуры

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

Изменение значения на клиенте

Коллекция параметров динамического списка доступна и на клиенте. Поэтому при смене поля на форме лишний серверный вызов не нужен:

&НаКлиенте
Процедура ГруппаПриИзменении(Элемент)
    Список.Параметры.УстановитьЗначениеПараметра("Группа", Группа);
КонецПроцедуры

Список перечитает данные сам. Вызывать Элементы.Список.Обновить() после установки параметра не нужно — это лишний запрос к серверу.

Как прочитать текущее значение

ЗначениеПараметра = Список.Параметры.НайтиЗначениеПараметра(
    Новый ПараметрКомпоновкиДанных("Группа"));
Если ЗначениеПараметра <> Неопределено Тогда
    ТекущаяГруппа = ЗначениеПараметра.Значение;
КонецЕсли;

Через найденный объект можно менять и значение, и флаг Использование. Но для обычной установки хватает УстановитьЗначениеПараметра.

Параметр или отбор: как фильтровать данные списка

Многие пишут условие в ГДЕ с параметром там, где нужен отбор. Результат — громоздкие конструкции вида «если пусто, то показать всё».

ЗадачаЧем решатьПочему
Дата остатков, период оборотовПараметрБез него запрос не имеет смысла
Документы текущего пользователяПараметрОбязательное условие
Фильтр по складу, который можно снятьОтборВыключается одним флагом
Список по владельцу при открытии из карточкиОтборПлатформа ставит его сама
Условие внутри соединенияПараметрОтбор на соединение не влияет

Отбор через типовую библиотеку (БСП, есть в БП 3.0, ЗУП 3.1, УТ 11 и других современных конфигурациях):

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

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

Без БСП тот же отбор пишется через элементы отбора компоновки:

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

Этот код при каждом вызове добавляет новый элемент. Если его поставить в ПриИзменении, отборы начнут копиться. Либо ищите существующий элемент по полю и меняйте его, либо используйте функцию БСП — она это делает сама.

Параметры виртуальных таблиц в динамическом списке

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

ВЫБРАТЬ
    Остатки.Номенклатура КАК Номенклатура,
    Остатки.Склад КАК Склад,
    Остатки.КоличествоОстаток КАК Остаток
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаОстатков, Склад = &Склад) КАК Остатки

Имя регистра здесь условное — подставьте свой регистр из конфигурации.

С датой остатков есть ловушка. Если передать дату 31.03.2026 0:00:00, движения за 31 марта в остаток не попадут. Остатки на конец дня передают через границу:

Список.Параметры.УстановитьЗначениеПараметра("ДатаОстатков",
    Новый Граница(КонецДня(ДатаОстатков), ВидГраницы.Включая));

Для оборотов нужны два параметра — &НачалоПериода и &КонецПериода. Конец периода тоже передают через КонецДня(), иначе последний день выпадает.

Почему условие пишут внутри скобок виртуальной таблицы, а не в ГДЕ:

  • ⚡ условие в параметрах таблицы отбирает данные до расчёта остатков, а ГДЕ — после;
  • ⚡ на больших регистрах разница во времени открытия формы бывает в разы;
  • ⚡ в ГДЕ нельзя корректно отобрать по полю, которого нет в итоговой таблице.

Для среза последних по регистру сведений передают &Период в СрезПоследних(&Период, ...). Если нужен срез на текущий момент, параметр периода можно не указывать вовсе — тогда берётся последнее значение.

Связанные списки: как передать параметр из одного в другой

Два списка на одной форме

Классика: сверху список контрагентов, снизу — договоры выбранного контрагента. Значение для второго списка берут из текущей строки первого в обработчике ПриАктивизацииСтроки.

&НаКлиенте
Процедура КонтрагентыПриАктивизацииСтроки(Элемент)
    ОтключитьОбработчикОжидания("ОбновитьДоговоры");
    ПодключитьОбработчикОжидания("ОбновитьДоговоры", 0.2, Истина);
КонецПроцедуры

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

Обработчик ожидания здесь — ключевой приём. Без него при прокрутке стрелками каждая строка вызывает перечитывание второго списка. С задержкой 0,2 секунды запрос уходит один раз, когда пользователь остановился.

ТекущаяСтрока у динамического списка с основной таблицей — ссылка на объект. Если основная таблица не задана, там будет служебный ключ строки, и сравнивать его со ссылкой бесполезно. Тогда берите поле из Элементы.Контрагенты.ТекущиеДанные.

Значение из формы, которая открывает список

Стандартный параметр формы списка Отбор платформа обрабатывает сама:

ПараметрыФормы = Новый Структура("Отбор", Новый Структура("Владелец", Контрагент));
ОткрытьФорму("Справочник.ДоговорыКонтрагентов.ФормаСписка", ПараметрыФормы);

Если нужен именно параметр запроса, добавьте в форму свой параметр (вкладка «Параметры» в редакторе формы), передайте его в ОткрытьФорму и в ПриСозданииНаСервере перенесите в список через УстановитьЗначениеПараметра.

Практические сценарии с параметрами

Необязательный параметр

Иногда условие должно стоять именно в запросе — например, внутри соединения. Тогда делают «пустое значение = без условия»:

ГДЕ
    (&Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
        ИЛИ Документы.Склад = &Склад)

Работает, но условие с ИЛИ мешает СУБД использовать индекс. Если такое условие можно заменить отбором — замените.

Список значений в параметре

Для условия В (&Склады) передают массив или список значений:

Склады = Новый Массив;
Склады.Добавить(ОсновнойСклад);
Склады.Добавить(СкладБрака);
Список.Параметры.УстановитьЗначениеПараметра("Склады", Склады);

Пустой массив даст пустой список. Если пустой набор должен означать «все склады», проверяйте это в коде и снимайте условие отбором.

Текущий пользователь

В конфигурациях на БСП текущего пользователя берут функцией Пользователи.ТекущийПользователь() на сервере и передают в параметр при создании формы. На клиенте этот параметр потом не меняют.

Период из поля «Стандартный период»

Для журналов и отчётов-списков удобно поставить над таблицей реквизит формы с типом СтандартныйПериод. Пользователь выбирает «Этот месяц» или произвольные даты, а код передаёт обе границы в запрос:

&НаКлиенте
Процедура ПериодПриИзменении(Элемент)
    Список.Параметры.УстановитьЗначениеПараметра("НачалоПериода", Период.ДатаНачала);
    Список.Параметры.УстановитьЗначениеПараметра("КонецПериода", КонецДня(Период.ДатаОкончания));
КонецПроцедуры

Тот же код вызывают и при создании формы, иначе первое открытие пройдёт без значений. Проще всего продублировать эти две строки в ПриСозданииНаСервере, предварительно заполнив период значением по умолчанию — например, текущим месяцем.

Как проверить, что значение дошло до списка

Поставьте точку останова после УстановитьЗначениеПараметра и в табло отладчика раскройте Список.Параметры.Элементы. У каждого элемента видно имя, значение и флаг Использование. Если нужного параметра в коллекции нет — значит, его нет в тексте запроса или список не переведён в режим произвольного запроса.

Производительность динамического списка с параметрами

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

  • 🚀 Основная таблица. Задайте её всегда, когда это возможно. Без неё платформа хуже управляет порционным чтением и ключами строк.
  • 🚀 Динамическое считывание данных. Флажок в свойствах списка. Включённый — список читает данные порциями по мере прокрутки. Выключать его стоит только для коротких списков, которые нужно обходить целиком.
  • 🚀 Условия в параметрах виртуальных таблиц, а не в ГДЕ.
  • 🚀 Одна установка на событие. Если меняются три параметра сразу, ставьте их подряд в одной процедуре, без промежуточных Обновить().
  • 🚀 Задержка при связанных списках через обработчик ожидания.
  • 🚀 Без лишних соединений. Каждое соединение с регистром в запросе выполняется для каждой порции. Поля из справочников через точку (Номенклатура.Родитель.Наименование) тоже порождают соединения.

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

Ошибки при установке параметров и как их найти

Диагностика: выберите симптом

Ещё одна неочевидная причина — установка параметра в ПриОткрытии вместо ПриСозданииНаСервере. Список успевает начать чтение с пустым значением. Результат — либо ошибка, либо два запроса вместо одного.

Не меняйте текст запроса динамического списка программно ради смены условия. Свойство ТекстЗапроса переписать можно, но после этого придётся заново проверять отборы, сортировку и сохранённые настройки пользователей. Для смены условия есть параметры и отборы.

Частые вопросы

Можно ли установить параметр динамического списка на клиенте?
Да. Коллекция Параметры доступна на клиенте, и после УстановитьЗначениеПараметра список перечитается сам, без отдельного серверного вызова.
Нужно ли вызывать Обновить() после установки параметра?
Нет. Смена значения параметра сама запускает перечитывание. Обновить() нужен, когда данные в базе изменились, а параметры остались прежними.
Можно ли выключить параметр, как отбор?
Параметр, который стоит в тексте запроса, должен иметь значение. Для необязательных условий используйте отбор или конструкцию с проверкой на пустое значение.
Почему пользователь не видит параметр в настройках списка?
Параметры запроса не выводятся в пользовательские настройки по умолчанию. Если пользователь должен их менять, сделайте реквизит формы и поле над списком.
Чувствителен ли регистр букв в имени параметра?
Встроенный язык 1С и язык запросов к регистру букв в именах не чувствительны. Но держите одно написание в запросе и в коде — так проще искать ошибки.