Параметры, отборы и сортировка динамического списка из кода: примеры для 1С 8.3

· 9 мин

Содержание

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

Самая частая ошибка — писать Элементы.Список.Параметры.... Элемент формы «Таблица» параметров не имеет, и платформа отвечает Поле объекта не обнаружено (Параметры). Параметры, отбор, порядок и текст запроса живут в реквизите типа ДинамическийСписок. Элемент отвечает только за отображение: колонки, видимость, текущую строку. Всё ниже относится к управляемым формам платформы 8.3 и одинаково работает в любой конфигурации.

Как устроен динамический список: реквизит, элемент и компоновка

Динамический список — это обёртка над системой компоновки данных. Поэтому у него те же объекты, что у отчёта на СКД: параметры, отбор, порядок, условное оформление, группировка.

Что за что отвечает:

  • 📦 Реквизит формы Список (тип ДинамическийСписок) — текст запроса, параметры, отбор, порядок, основная таблица.
  • 🖥 Элемент формы Элементы.Список (тип «Таблица формы») — колонки, текущая строка, режим выделения, команда обновления.
  • ⚙️ Компоновщик настроек Список.КомпоновщикНастроек — три слоя настроек: основные, фиксированные и пользовательские.

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

Свойства Список.Отбор и Список.Порядок — короткий доступ к отбору и порядку основных настроек. Для разовой задачи их хватает, лезть в КомпоновщикНастроек не обязательно.

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

Параметр появится в коллекции Список.Параметры только тогда, когда он есть в тексте запроса. Порядок действий:

  1. Откройте форму в Конфигураторе, выделите реквизит Список и в его свойствах включите Произвольный запрос.
  2. Откройте текст запроса и добавьте условие с параметром, например ГДЕ Документ.Организация = &Организация.
  3. Укажите Основную таблицу, если список должен открывать карточку объекта по двойному щелчку.
  4. Сохраните форму и перейдите в модуль.

Где заполнять параметр:

СитуацияОбработчикКонтекст
Значение известно при открытии формыПриСозданииНаСервересервер
Значение пришло в параметрах формыПриСозданииНаСервере, из Параметры.<Имя>сервер
Пользователь меняет значение на формеПриИзменении поля формыклиент или сервер
Значение берётся из сохранённых настроек формыПриЗагрузкеДанныхИзНастроекНаСервересервер

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

Установка параметра динамического списка кодом: примеры

Базовый вариант

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	Список.Параметры.УстановитьЗначениеПараметра("Организация", Параметры.Организация);
	Список.Параметры.УстановитьЗначениеПараметра("ДатаНачала", НачалоМесяца(ТекущаяДатаСеанса()));

КонецПроцедуры

Имя передаётся строкой без амперсанда. Регистр букв роли не играет, но ошибка в одной букве даст параметр, которого нет в запросе.

Параметр меняется на форме

Пример: над списком есть поле ОтборСклад, пользователь выбирает склад, список перечитывается.

&НаКлиенте
Процедура ОтборСкладПриИзменении(Элемент)

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

КонецПроцедуры

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

Параметр-список значений

Для условия ГДЕ Номенклатура.Родитель В (&Группы) передайте массив или список значений:

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

НайтиПоНаименованию здесь только для примера. В рабочем коде берите ссылки из реквизитов формы или предопределённых элементов — поиск по имени ломается при первом переименовании.

Параметр-период и дата среза

С датами чаще всего ошибаются на границе дня. Если в запросе стоит Документ.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания, а в ДатаОкончания передать 31.03 без времени, документы за 31 марта после полуночи в список не попадут. Передавайте конец дня:

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

Здесь Период — реквизит формы типа «Стандартный период». Для среза последних в регистре сведений логика та же: дата 01.04.2025 00:00:00 вернёт цены, действовавшие на начало дня, без изменений, внесённых в течение 1 апреля.

Значение из сохранённых настроек формы

Если реквизит-отбор над списком сохраняется между сеансами, параметр нужно пересчитать после загрузки настроек, иначе он останется от ПриСозданииНаСервере:

&НаСервере
Процедура ПриЗагрузкеДанныхИзНастроекНаСервере(Настройки)

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

КонецПроцедуры

Реквизит ОтборСклад для этого отмечают как сохраняемый: флажок в колонке «Сохраняемые данные» списка реквизитов формы.

Через коллекцию параметров

Иногда нужно не просто записать значение, а проверить, есть ли параметр, или выключить его использование:

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

Проверка на Неопределено защищает от ситуации, когда текст запроса поменяли, а параметр из него убрали.

Готовая функция БСП

В типовых конфигурациях на Библиотеке стандартных подсистем есть обёртка:

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

Она работает и на клиенте, и на сервере. Если параметра в запросе нет, ошибки не будет. В доработках типовых баз лучше пользоваться ей: такой код проще читать и сопровождать.

Программные отборы динамического списка

Параметр и отбор решают похожие задачи, но по-разному.

СпособГде работает условиеВидит ли пользовательКогда выбирать
Параметр запроса &Имявнутри запроса, в том числе во вложенных таблицах и соединенияхнетусловие участвует в соединении, в виртуальной таблице, в вычисляемом поле
Отбор Список.Отборповерх результата запросада, если не скрытобычное условие по полю списка
Параметр формы Отбор при открытииавтоматически превращается в отбордаоткрыть стандартную форму списка с отбором из другого места

Хороший пример для параметра — дата среза в виртуальной таблице: РегистрСведений.Цены.СрезПоследних(&Дата, ). Отбором такое не сделать.

Отбор на чистой платформе

&НаСервере
Процедура УстановитьОтборПоОрганизации(Организация)

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

КонецПроцедуры

У такого кода есть подвох: каждый вызов добавляет новый элемент. Вызовите процедуру три раза — получите три условия «Организация равно…», и список опустеет, если значения разные. Перед добавлением ищите и удаляйте старый элемент по ЛевоеЗначение.

Режим Недоступный скрывает условие от пользователя и не даёт его снять. Если отбор должен быть виден, но не редактироваться, выберите БыстрыйДоступ или Обычный по задаче.

Отбор через БСП

Функция сама найдёт прежний элемент по полю и перезапишет его, а не будет копить дубли:

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

Последний аргумент — Использование. Передав ЗначениеЗаполнено(Организация), вы автоматически выключаете отбор, когда поле на форме очистили. Снять отбор целиком помогает ОбщегоНазначенияКлиентСервер.УдалитьЭлементыГруппыОтбораДинамическогоСписка(Список, "Организация").

Отбор при открытии формы

Из другой формы список открывают сразу с отбором — обработчик в форме списка писать не нужно:

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

Платформа сама наложит отбор на основной реквизит-список. Имя поля в структуре должно совпадать с полем списка.

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

Видимость колонок

Колонки — это элементы формы, поэтому работают с ними через Элементы:

Элементы.СписокСклад.Видимость = Не ЗначениеЗаполнено(ОтборСклад);

Смысл примера: если склад уже выбран в отборе, колонка «Склад» в списке не нужна.

Скрытая колонка не убирает поле из запроса. Обратная задача — поле не выведено колонкой, но нужно в коде, например в ПриАктивизацииСтроки. Без колонки платформа может его не выбирать, и Элементы.Список.ТекущиеДанные.Поле вернёт пустое значение. Решение:

Список.УстановитьОбязательноеИспользование("Ответственный", Истина);

Сортировка

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

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

Подмена текста запроса

Если условие слишком сложное для параметра, текст запроса можно собрать кодом:

Список.ПроизвольныйЗапрос = Истина;
Список.ОсновнаяТаблица = "Документ.РеализацияТоваровУслуг";
Список.ТекстЗапроса = ТекстЗапросаСписка();
Список.Параметры.УстановитьЗначениеПараметра("Организация", Организация);

Параметры заполняйте после присвоения текста запроса. Новый текст пересоздаёт коллекцию параметров, и значения, заданные раньше, теряются.

События чтения и скорость динамического списка

Событие ПриПолученииДанныхНаСервере

Когда колонку нельзя вычислить в запросе (значение берётся из внешней системы, из сложного расчёта), используйте событие таблицы ПриПолученииДанныхНаСервере. Оно срабатывает на каждую порцию строк, которую список читает с сервера.

&НаСервереБезКонтекста
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)

	Для Каждого КлючИСтрока Из Строки Цикл
		ДанныеСтроки = КлючИСтрока.Значение.Данные;
		ДанныеСтроки.Комментарий = СокрЛП(ДанныеСтроки.Комментарий);
	КонецЦикла;

КонецПроцедуры

Правила для этого обработчика:

  • 🚫 он без контекста формы: реквизиты формы и Элементы недоступны;
  • 🧮 поле, которое заполняете, должно быть в запросе списка (хотя бы как пустое значение нужного типа);
  • 🐢 никаких запросов «на каждую строку» — соберите ключи из Строки в массив и получите данные одним запросом.

Пока у списка есть этот обработчик, отбор и сортировка по заполненным в нём полям работать не будут: платформа сортирует и отбирает в СУБД, а значения появляются уже после чтения.

Что ускоряет список

  • ⚡ Динамическое считывание данных — флажок в свойствах реквизита. Список читает только видимую порцию строк, а не всю таблицу. Отключать его стоит лишь при очень маленьком объёме данных.
  • 🔑 Основная таблица — с ней платформа читает порции по ключу и быстрее позиционируется на текущей строке.
  • 🧱 Параметр вместо отбора по вычисляемому полю — условие уходит внутрь запроса, и СУБД может использовать индекс.
  • 📉 Без лишних соединений — каждое ЛЕВОЕ СОЕДИНЕНИЕ выполняется при каждом листании списка.

Когда параметр «не работает»: разбор симптомов

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

Отдельный случай — расширение конфигурации . Если вы меняете параметры типовой формы из расширения, ставьте установку в обработчик с аннотацией &После("ПриСозданииНаСервере"). Так типовой код отработает первым, и ваши значения его не перезатрут.

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

Можно ли установить параметр динамического списка на клиенте?
Да. Реквизит списка доступен на клиенте, метод УстановитьЗначениеПараметра работает там же. Список сам вызовет сервер и перечитает данные.
Чем параметр списка отличается от параметра формы?
Параметр формы приходит при открытии (Параметры.Организация) и живёт только в ПриСозданииНаСервере. Параметр списка — часть запроса. Обычно первый передают во второй.
Как передать в параметр пустое значение, чтобы показать все записи?
Пишите условие так: ГДЕ (&Склад = ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка) ИЛИ Остатки.Склад = &Склад). Пустой склад — все строки, заполненный — только его.
Можно ли добавить новый параметр без изменения текста запроса?
Нет. Коллекция параметров строится из текста запроса. Добавьте &Имя в запрос — параметр появится автоматически.
Как узнать, какое значение параметра сейчас стоит в списке?
Найдите его через Список.Параметры.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Склад")) и прочитайте свойства Значение и Использование. Удобно в отладчике: точка останова в обработчике и вычисление выражения.
Нужно ли вызывать Обновить() после установки параметра?
Нет, изменение параметра или отбора само перечитывает список. Обновить() нужен, когда изменились данные в базе, а настройки остались прежними.