Параметры динамического списка в управляемой форме: код, отборы, связанные списки
Содержание
Значение параметра динамического списка устанавливают одной строкой: Список.Параметры.УстановитьЗначениеПараметра("Склад", Склад);. Вызов ставят в обработчик формы ПриСозданииНаСервере, а при смене значения пользователем — в обработчик ПриИзменении реквизита. Сам параметр должен быть в тексте запроса списка в виде &Склад, поэтому у списка включают флажок «Произвольный запрос».
Типичная ситуация: программист делает форму остатков, где сверху поле «Склад», а снизу список товаров. В Конфигураторе всё собирается за пять минут, а при открытии формы появляется ошибка про не установленное значение параметра. Или ошибки нет, но список пустой, хотя данные в базе есть. Почти всегда причина в том, где и как задано значение.
Что такое параметр динамического списка и откуда он берётся
Динамический список работает на механизме компоновки данных. Его запрос — это не обычный Запрос, а схема, которую платформа достраивает сама: добавляет отборы, сортировку, порции чтения. Параметр — именованное значение, которое подставляется в текст запроса вместо &ИмяПараметра.
Параметры появляются только в одном случае: когда у списка задан произвольный запрос и в его тексте есть хотя бы один &. У списка, построенного просто по основной таблице (например, Справочник.Номенклатура без своего запроса), коллекция параметров пустая.
Чем параметр отличается от отбора:
- 🔹 параметр — часть текста запроса; без значения запрос не выполнится;
- 🔹 отбор — условие, которое компоновка добавляет поверх запроса; его можно включать и выключать;
- 🔹 параметр виртуальной таблицы — частный случай параметра: период остатков, условие внутри
Остатки(...),Обороты(...),СрезПоследних(...).
Отсюда простое правило. Если условие обязательно и без него список не имеет смысла (дата остатков, текущий пользователь) — это параметр. Если условие необязательное и пользователь может его снять — это отбор.
Как задать значение параметра: конструктор и программный код
Подготовка списка в Конфигураторе
- Откройте форму в Конфигураторе и добавьте реквизит формы с типом
ДинамическийСписок. - Откройте свойства реквизита (двойной щелчок по нему) и установите флажок «Произвольный запрос».
- Напишите текст запроса или откройте конструктор запроса. Параметры записывайте через
&. - Укажите «Основную таблицу» — ту, ссылки которой выводит список. Это важно для производительности и для работы команд «Создать», «Изменить».
- Перетащите реквизит на форму, чтобы появилась таблица.
Пример запроса:
ВЫБРАТЬ
Номенклатура.Ссылка КАК Ссылка,
Номенклатура.Наименование КАК Наименование,
Номенклатура.Артикул КАК Артикул
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
Номенклатура.Родитель = &Группа
Установка значения при открытии формы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Группа = Параметры.Группа; // реквизит формы, пришёл при открытии
Список.Параметры.УстановитьЗначениеПараметра("Группа", Группа);
КонецПроцедуры
Метод принимает имя параметра строкой и значение. Флаг использования он ставит сам, отдельно включать его не нужно.
Изменение значения на клиенте
Коллекция параметров динамического списка доступна и на клиенте. Поэтому при смене поля на форме лишний серверный вызов не нужен:
&НаКлиенте
Процедура ГруппаПриИзменении(Элемент)
Список.Параметры.УстановитьЗначениеПараметра("Группа", Группа);
КонецПроцедуры
Список перечитает данные сам. Вызывать Элементы.Список.Обновить() после установки параметра не нужно — это лишний запрос к серверу.
Как прочитать текущее значение
ЗначениеПараметра = Список.Параметры.НайтиЗначениеПараметра(
Новый ПараметрКомпоновкиДанных("Группа"));
Если ЗначениеПараметра <> Неопределено Тогда
ТекущаяГруппа = ЗначениеПараметра.Значение;
КонецЕсли;
Через найденный объект можно менять и значение, и флаг Использование. Но для обычной установки хватает УстановитьЗначениеПараметра.
Параметр или отбор: как фильтровать данные списка
Многие пишут условие в ГДЕ с параметром там, где нужен отбор. Результат — громоздкие конструкции вида «если пусто, то показать всё».
| Задача | Чем решать | Почему |
|---|---|---|
| Дата остатков, период оборотов | Параметр | Без него запрос не имеет смысла |
| Документы текущего пользователя | Параметр | Обязательное условие |
| Фильтр по складу, который можно снять | Отбор | Выключается одним флагом |
| Список по владельцу при открытии из карточки | Отбор | Платформа ставит его сама |
| Условие внутри соединения | Параметр | Отбор на соединение не влияет |
Отбор через типовую библиотеку (БСП, есть в БП 3.0, ЗУП 3.1, УТ 11 и других современных конфигурациях):
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
Список, "Склад", Склад, ВидСравненияКомпоновкиДанных.Равно, , ЗначениеЗаполнено(Склад));
Последний аргумент — использование. Пустой склад выключает отбор, и список показывает всё.
Без БСП тот же отбор пишется через элементы отбора компоновки:
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Склад");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Склад;
ЭлементОтбора.Использование = ЗначениеЗаполнено(Склад);
Этот код при каждом вызове добавляет новый элемент. Если его поставить в ПриИзменении, отборы начнут копиться. Либо ищите существующий элемент по полю и меняйте его, либо используйте функцию БСП — она это делает сама.
Параметры виртуальных таблиц в динамическом списке
Остатки, обороты и срезы регистров — главная причина, по которой берутся за произвольный запрос. Значения в параметры виртуальных таблиц передают так же, через &:
ВЫБРАТЬ
Остатки.Номенклатура КАК Номенклатура,
Остатки.Склад КАК Склад,
Остатки.КоличествоОстаток КАК Остаток
ИЗ
РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаОстатков, Склад = &Склад) КАК Остатки
Имя регистра здесь условное — подставьте свой регистр из конфигурации.
С датой остатков есть ловушка. Если передать дату 31.03.2026 0:00:00, движения за 31 марта в остаток не попадут. Остатки на конец дня передают через границу:
Список.Параметры.УстановитьЗначениеПараметра("ДатаОстатков",
Новый Граница(КонецДня(ДатаОстатков), ВидГраницы.Включая));
Для оборотов нужны два параметра — &НачалоПериода и &КонецПериода. Конец периода тоже передают через КонецДня(), иначе последний день выпадает.
Почему условие пишут внутри скобок виртуальной таблицы, а не в ГДЕ:
- ⚡ условие в параметрах таблицы отбирает данные до расчёта остатков, а
ГДЕ— после; - ⚡ на больших регистрах разница во времени открытия формы бывает в разы;
- ⚡ в
ГДЕнельзя корректно отобрать по полю, которого нет в итоговой таблице.
Для среза последних по регистру сведений передают &Период в СрезПоследних(&Период, ...). Если нужен срез на текущий момент, параметр периода можно не указывать вовсе — тогда берётся последнее значение.
Связанные списки: как передать параметр из одного в другой
Два списка на одной форме
Классика: сверху список контрагентов, снизу — договоры выбранного контрагента. Значение для второго списка берут из текущей строки первого в обработчике ПриАктивизацииСтроки.
&НаКлиенте
Процедура КонтрагентыПриАктивизацииСтроки(Элемент)
ОтключитьОбработчикОжидания("ОбновитьДоговоры");
ПодключитьОбработчикОжидания("ОбновитьДоговоры", 0.2, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьДоговоры()
ТекущаяСтрока = Элементы.Контрагенты.ТекущаяСтрока;
Договоры.Параметры.УстановитьЗначениеПараметра("Владелец", ТекущаяСтрока);
КонецПроцедуры
Обработчик ожидания здесь — ключевой приём. Без него при прокрутке стрелками каждая строка вызывает перечитывание второго списка. С задержкой 0,2 секунды запрос уходит один раз, когда пользователь остановился.
ТекущаяСтрока у динамического списка с основной таблицей — ссылка на объект. Если основная таблица не задана, там будет служебный ключ строки, и сравнивать его со ссылкой бесполезно. Тогда берите поле из Элементы.Контрагенты.ТекущиеДанные.
Значение из формы, которая открывает список
Стандартный параметр формы списка Отбор платформа обрабатывает сама:
ПараметрыФормы = Новый Структура("Отбор", Новый Структура("Владелец", Контрагент));
ОткрытьФорму("Справочник.ДоговорыКонтрагентов.ФормаСписка", ПараметрыФормы);
Если нужен именно параметр запроса, добавьте в форму свой параметр (вкладка «Параметры» в редакторе формы), передайте его в ОткрытьФорму и в ПриСозданииНаСервере перенесите в список через УстановитьЗначениеПараметра.
Практические сценарии с параметрами
Необязательный параметр
Иногда условие должно стоять именно в запросе — например, внутри соединения. Тогда делают «пустое значение = без условия»:
ГДЕ
(&Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)
ИЛИ Документы.Склад = &Склад)
Работает, но условие с ИЛИ мешает СУБД использовать индекс. Если такое условие можно заменить отбором — замените.
Список значений в параметре
Для условия В (&Склады) передают массив или список значений:
Склады = Новый Массив;
Склады.Добавить(ОсновнойСклад);
Склады.Добавить(СкладБрака);
Список.Параметры.УстановитьЗначениеПараметра("Склады", Склады);
Пустой массив даст пустой список. Если пустой набор должен означать «все склады», проверяйте это в коде и снимайте условие отбором.
Текущий пользователь
В конфигурациях на БСП текущего пользователя берут функцией Пользователи.ТекущийПользователь() на сервере и передают в параметр при создании формы. На клиенте этот параметр потом не меняют.
Период из поля «Стандартный период»
Для журналов и отчётов-списков удобно поставить над таблицей реквизит формы с типом СтандартныйПериод. Пользователь выбирает «Этот месяц» или произвольные даты, а код передаёт обе границы в запрос:
&НаКлиенте
Процедура ПериодПриИзменении(Элемент)
Список.Параметры.УстановитьЗначениеПараметра("НачалоПериода", Период.ДатаНачала);
Список.Параметры.УстановитьЗначениеПараметра("КонецПериода", КонецДня(Период.ДатаОкончания));
КонецПроцедуры
Тот же код вызывают и при создании формы, иначе первое открытие пройдёт без значений. Проще всего продублировать эти две строки в ПриСозданииНаСервере, предварительно заполнив период значением по умолчанию — например, текущим месяцем.
Как проверить, что значение дошло до списка
Поставьте точку останова после УстановитьЗначениеПараметра и в табло отладчика раскройте Список.Параметры.Элементы. У каждого элемента видно имя, значение и флаг Использование. Если нужного параметра в коллекции нет — значит, его нет в тексте запроса или список не переведён в режим произвольного запроса.
Производительность динамического списка с параметрами
Произвольный запрос сам по себе не замедляет список. Тормозит то, что в нём написано, и то, как его настроили.
- 🚀 Основная таблица. Задайте её всегда, когда это возможно. Без неё платформа хуже управляет порционным чтением и ключами строк.
- 🚀 Динамическое считывание данных. Флажок в свойствах списка. Включённый — список читает данные порциями по мере прокрутки. Выключать его стоит только для коротких списков, которые нужно обходить целиком.
- 🚀 Условия в параметрах виртуальных таблиц, а не в
ГДЕ. - 🚀 Одна установка на событие. Если меняются три параметра сразу, ставьте их подряд в одной процедуре, без промежуточных
Обновить(). - 🚀 Задержка при связанных списках через обработчик ожидания.
- 🚀 Без лишних соединений. Каждое соединение с регистром в запросе выполняется для каждой порции. Поля из справочников через точку (
Номенклатура.Родитель.Наименование) тоже порождают соединения.
Чтобы найти узкое место, включите замер производительности в режиме 1С:Предприятие и откройте форму. Строка с получением данных динамического списка покажет, сколько времени ушло на запрос.
Ошибки при установке параметров и как их найти
Ещё одна неочевидная причина — установка параметра в ПриОткрытии вместо ПриСозданииНаСервере. Список успевает начать чтение с пустым значением. Результат — либо ошибка, либо два запроса вместо одного.
Не меняйте текст запроса динамического списка программно ради смены условия. Свойство ТекстЗапроса переписать можно, но после этого придётся заново проверять отборы, сортировку и сохранённые настройки пользователей. Для смены условия есть параметры и отборы.
Частые вопросы
Можно ли установить параметр динамического списка на клиенте?
Параметры доступна на клиенте, и после УстановитьЗначениеПараметра список перечитается сам, без отдельного серверного вызова.Нужно ли вызывать Обновить() после установки параметра?
Обновить() нужен, когда данные в базе изменились, а параметры остались прежними.