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