Параметры, отборы и сортировка динамического списка из кода: примеры для 1С 8.3
Содержание
Параметр динамического списка устанавливают через реквизит формы, а не через элемент: Список.Параметры.УстановитьЗначениеПараметра("Организация", Организация). Делают это в обработчике ПриСозданииНаСервере, до того как список первый раз прочитает данные. Сам параметр должен быть в тексте запроса списка в виде &Организация, а у списка включён флажок «Произвольный запрос».
Самая частая ошибка — писать Элементы.Список.Параметры.... Элемент формы «Таблица» параметров не имеет, и платформа отвечает Поле объекта не обнаружено (Параметры). Параметры, отбор, порядок и текст запроса живут в реквизите типа ДинамическийСписок. Элемент отвечает только за отображение: колонки, видимость, текущую строку. Всё ниже относится к управляемым формам платформы 8.3 и одинаково работает в любой конфигурации.
Как устроен динамический список: реквизит, элемент и компоновка
Динамический список — это обёртка над системой компоновки данных. Поэтому у него те же объекты, что у отчёта на СКД: параметры, отбор, порядок, условное оформление, группировка.
Что за что отвечает:
- 📦 Реквизит формы
Список(типДинамическийСписок) — текст запроса, параметры, отбор, порядок, основная таблица. - 🖥 Элемент формы
Элементы.Список(тип «Таблица формы») — колонки, текущая строка, режим выделения, команда обновления. - ⚙️ Компоновщик настроек
Список.КомпоновщикНастроек— три слоя настроек: основные, фиксированные и пользовательские.
Последний пункт важен для отборов. Отбор, который вы ставите кодом, накладывается на то, что пользователь сам выставил в списке и сохранил. Если поле одно и то же, итог может удивить. Как этого избежать — в разделе про отборы.
Свойства Список.Отбор и Список.Порядок — короткий доступ к отбору и порядку основных настроек. Для разовой задачи их хватает, лезть в КомпоновщикНастроек не обязательно.
Подготовка: параметр в запросе и место, где его заполнять
Параметр появится в коллекции Список.Параметры только тогда, когда он есть в тексте запроса. Порядок действий:
- Откройте форму в Конфигураторе, выделите реквизит
Списоки в его свойствах включите Произвольный запрос. - Откройте текст запроса и добавьте условие с параметром, например
ГДЕ Документ.Организация = &Организация. - Укажите Основную таблицу, если список должен открывать карточку объекта по двойному щелчку.
- Сохраните форму и перейдите в модуль.
Где заполнять параметр:
| Ситуация | Обработчик | Контекст |
|---|---|---|
| Значение известно при открытии формы | ПриСозданииНаСервере | сервер |
| Значение пришло в параметрах формы | ПриСозданииНаСервере, из Параметры.<Имя> | сервер |
| Пользователь меняет значение на форме | ПриИзменении поля формы | клиент или сервер |
| Значение берётся из сохранённых настроек формы | ПриЗагрузкеДанныхИзНастроекНаСервере | сервер |
Если параметр остался без значения, а запрос его использует, список не покажет нужных строк. Поэтому заполняйте каждый параметр запроса ещё до первого чтения, хотя бы значением по умолчанию.
Установка параметра динамического списка кодом: примеры
Базовый вариант
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Список.Параметры.УстановитьЗначениеПараметра("Организация", Параметры.Организация);
Список.Параметры.УстановитьЗначениеПараметра("ДатаНачала", НачалоМесяца(ТекущаяДатаСеанса()));
КонецПроцедуры
Имя передаётся строкой без амперсанда. Регистр букв роли не играет, но ошибка в одной букве даст параметр, которого нет в запросе.
Параметр меняется на форме
Пример: над списком есть поле ОтборСклад, пользователь выбирает склад, список перечитывается.
&НаКлиенте
Процедура ОтборСкладПриИзменении(Элемент)
Список.Параметры.УстановитьЗначениеПараметра("Склад", ОтборСклад);
КонецПроцедуры
Отдельно вызывать Элементы.Список.Обновить() не нужно: изменение параметра само заставляет список перечитать данные. Работать с параметрами можно и на клиенте — реквизит списка там доступен.
Параметр-список значений
Для условия ГДЕ Номенклатура.Родитель В (&Группы) передайте массив или список значений:
Группы = Новый Массив;
Группы.Добавить(Справочники.Номенклатура.НайтиПоНаименованию("Материалы"));
Группы.Добавить(Справочники.Номенклатура.НайтиПоНаименованию("Товары"));
Список.Параметры.УстановитьЗначениеПараметра("Группы", Группы);
НайтиПоНаименованию здесь только для примера. В рабочем коде берите ссылки из реквизитов формы или предопределённых элементов — поиск по имени ломается при первом переименовании.
Параметр-период и дата среза
С датами чаще всего ошибаются на границе дня. Если в запросе стоит Документ.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания, а в ДатаОкончания передать 31.03 без времени, документы за 31 марта после полуночи в список не попадут. Передавайте конец дня:
Список.Параметры.УстановитьЗначениеПараметра("ДатаНачала", Период.ДатаНачала);
Список.Параметры.УстановитьЗначениеПараметра("ДатаОкончания", КонецДня(Период.ДатаОкончания));
Здесь Период — реквизит формы типа «Стандартный период». Для среза последних в регистре сведений логика та же: дата 01.04.2025 00:00:00 вернёт цены, действовавшие на начало дня, без изменений, внесённых в течение 1 апреля.
Значение из сохранённых настроек формы
Если реквизит-отбор над списком сохраняется между сеансами, параметр нужно пересчитать после загрузки настроек, иначе он останется от ПриСозданииНаСервере:
&НаСервере
Процедура ПриЗагрузкеДанныхИзНастроекНаСервере(Настройки)
ОтборСклад = Настройки.Получить("ОтборСклад");
Список.Параметры.УстановитьЗначениеПараметра("Склад", ОтборСклад);
КонецПроцедуры
Реквизит ОтборСклад для этого отмечают как сохраняемый: флажок в колонке «Сохраняемые данные» списка реквизитов формы.
Через коллекцию параметров
Иногда нужно не просто записать значение, а проверить, есть ли параметр, или выключить его использование:
Параметр = Список.Параметры.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Склад"));
Если Параметр <> Неопределено Тогда
Параметр.Значение = ОтборСклад;
Параметр.Использование = ЗначениеЗаполнено(ОтборСклад);
КонецЕсли;
Проверка на Неопределено защищает от ситуации, когда текст запроса поменяли, а параметр из него убрали.
Готовая функция БСП
В типовых конфигурациях на Библиотеке стандартных подсистем есть обёртка:
ОбщегоНазначенияКлиентСервер.УстановитьПараметрДинамическогоСписка(Список, "Склад", ОтборСклад);
Она работает и на клиенте, и на сервере. Если параметра в запросе нет, ошибки не будет. В доработках типовых баз лучше пользоваться ей: такой код проще читать и сопровождать.
Программные отборы динамического списка
Параметр и отбор решают похожие задачи, но по-разному.
| Способ | Где работает условие | Видит ли пользователь | Когда выбирать |
|---|---|---|---|
Параметр запроса &Имя | внутри запроса, в том числе во вложенных таблицах и соединениях | нет | условие участвует в соединении, в виртуальной таблице, в вычисляемом поле |
Отбор Список.Отбор | поверх результата запроса | да, если не скрыт | обычное условие по полю списка |
Параметр формы Отбор при открытии | автоматически превращается в отбор | да | открыть стандартную форму списка с отбором из другого места |
Хороший пример для параметра — дата среза в виртуальной таблице: РегистрСведений.Цены.СрезПоследних(&Дата, ). Отбором такое не сделать.
Отбор на чистой платформе
&НаСервере
Процедура УстановитьОтборПоОрганизации(Организация)
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Организация");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Организация;
ЭлементОтбора.Использование = Истина;
ЭлементОтбора.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
КонецПроцедуры
У такого кода есть подвох: каждый вызов добавляет новый элемент. Вызовите процедуру три раза — получите три условия «Организация равно…», и список опустеет, если значения разные. Перед добавлением ищите и удаляйте старый элемент по ЛевоеЗначение.
Режим Недоступный скрывает условие от пользователя и не даёт его снять. Если отбор должен быть виден, но не редактироваться, выберите БыстрыйДоступ или Обычный по задаче.
Отбор через БСП
Функция сама найдёт прежний элемент по полю и перезапишет его, а не будет копить дубли:
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
Список, "Организация", Организация, ВидСравненияКомпоновкиДанных.Равно, , ЗначениеЗаполнено(Организация));
Последний аргумент — Использование. Передав ЗначениеЗаполнено(Организация), вы автоматически выключаете отбор, когда поле на форме очистили. Снять отбор целиком помогает ОбщегоНазначенияКлиентСервер.УдалитьЭлементыГруппыОтбораДинамическогоСписка(Список, "Организация").
Отбор при открытии формы
Из другой формы список открывают сразу с отбором — обработчик в форме списка писать не нужно:
ПараметрыФормы = Новый Структура("Отбор", Новый Структура("Контрагент", Контрагент));
ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаСписка", ПараметрыФормы);
Платформа сама наложит отбор на основной реквизит-список. Имя поля в структуре должно совпадать с полем списка.
Колонки, сортировка и текст запроса из кода
Видимость колонок
Колонки — это элементы формы, поэтому работают с ними через Элементы:
Элементы.СписокСклад.Видимость = Не ЗначениеЗаполнено(ОтборСклад);
Смысл примера: если склад уже выбран в отборе, колонка «Склад» в списке не нужна.
Скрытая колонка не убирает поле из запроса. Обратная задача — поле не выведено колонкой, но нужно в коде, например в ПриАктивизацииСтроки. Без колонки платформа может его не выбирать, и Элементы.Список.ТекущиеДанные.Поле вернёт пустое значение. Решение:
Список.УстановитьОбязательноеИспользование("Ответственный", Истина);
Сортировка
Список.Порядок.Элементы.Очистить();
ЭлементПорядка = Список.Порядок.Элементы.Добавить(Тип("ЭлементПорядкаКомпоновкиДанных"));
ЭлементПорядка.Поле = Новый ПолеКомпоновкиДанных("Дата");
ЭлементПорядка.ТипУпорядочивания = НаправлениеСортировкиКомпоновкиДанных.Убыв;
ЭлементПорядка.Использование = Истина;
Очистить() стоит в начале не просто так: без него новый порядок встанет после уже существующего, и первым останется прежний ключ сортировки.
Подмена текста запроса
Если условие слишком сложное для параметра, текст запроса можно собрать кодом:
Список.ПроизвольныйЗапрос = Истина;
Список.ОсновнаяТаблица = "Документ.РеализацияТоваровУслуг";
Список.ТекстЗапроса = ТекстЗапросаСписка();
Список.Параметры.УстановитьЗначениеПараметра("Организация", Организация);
Параметры заполняйте после присвоения текста запроса. Новый текст пересоздаёт коллекцию параметров, и значения, заданные раньше, теряются.
События чтения и скорость динамического списка
Событие ПриПолученииДанныхНаСервере
Когда колонку нельзя вычислить в запросе (значение берётся из внешней системы, из сложного расчёта), используйте событие таблицы ПриПолученииДанныхНаСервере. Оно срабатывает на каждую порцию строк, которую список читает с сервера.
&НаСервереБезКонтекста
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
Для Каждого КлючИСтрока Из Строки Цикл
ДанныеСтроки = КлючИСтрока.Значение.Данные;
ДанныеСтроки.Комментарий = СокрЛП(ДанныеСтроки.Комментарий);
КонецЦикла;
КонецПроцедуры
Правила для этого обработчика:
- 🚫 он без контекста формы: реквизиты формы и
Элементынедоступны; - 🧮 поле, которое заполняете, должно быть в запросе списка (хотя бы как пустое значение нужного типа);
- 🐢 никаких запросов «на каждую строку» — соберите ключи из
Строкив массив и получите данные одним запросом.
Пока у списка есть этот обработчик, отбор и сортировка по заполненным в нём полям работать не будут: платформа сортирует и отбирает в СУБД, а значения появляются уже после чтения.
Что ускоряет список
- ⚡ Динамическое считывание данных — флажок в свойствах реквизита. Список читает только видимую порцию строк, а не всю таблицу. Отключать его стоит лишь при очень маленьком объёме данных.
- 🔑 Основная таблица — с ней платформа читает порции по ключу и быстрее позиционируется на текущей строке.
- 🧱 Параметр вместо отбора по вычисляемому полю — условие уходит внутрь запроса, и СУБД может использовать индекс.
- 📉 Без лишних соединений — каждое
ЛЕВОЕ СОЕДИНЕНИЕвыполняется при каждом листании списка.
Когда параметр «не работает»: разбор симптомов
Элементы.Список.Параметры на Список.Параметры — параметры есть только у реквизита.ПриОткрытии или позже, а запрос его уже использовал. Перенесите установку в ПриСозданииНаСервере, задав значение по умолчанию.ПриЗагрузкеДанныхИзНастроекНаСервере или исключите реквизит из сохраняемых.НайтиЗначениеПараметра и порядок строк кода.РежимОтображения = Недоступный.Отдельный случай — расширение конфигурации
. Если вы меняете параметры типовой формы из расширения, ставьте установку в обработчик с аннотацией &После("ПриСозданииНаСервере"). Так типовой код отработает первым, и ваши значения его не перезатрут.
Частые вопросы
Можно ли установить параметр динамического списка на клиенте?
УстановитьЗначениеПараметра работает там же. Список сам вызовет сервер и перечитает данные.Чем параметр списка отличается от параметра формы?
Параметры.Организация) и живёт только в ПриСозданииНаСервере. Параметр списка — часть запроса. Обычно первый передают во второй.Как передать в параметр пустое значение, чтобы показать все записи?
ГДЕ (&Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка) ИЛИ Остатки.Склад = &Склад). Пустой склад — все строки, заполненный — только его.Можно ли добавить новый параметр без изменения текста запроса?
&Имя в запрос — параметр появится автоматически.Как узнать, какое значение параметра сейчас стоит в списке?
Список.Параметры.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Склад")) и прочитайте свойства Значение и Использование. Удобно в отладчике: точка останова в обработчике и вычисление выражения.Нужно ли вызывать Обновить() после установки параметра?
Обновить() нужен, когда изменились данные в базе, а настройки остались прежними.