При разработке расширений для типовых конфигураций, таких как УТ 11.5, ERP или КА, часто возникает необходимость дополнить стандартные журналы документов визуальными индикаторами. Например, вывести иконку скрепки, если к документу присоединены файлы — для этого подойдёт расширение для вывода значка скрепки в журналах. В данной статье мы подробно разберем, как правильно добавить программную колонку в ДинамическийСписок и как эффективно заполнить её данными, избегая проблем с производительностью и контекстом выполнения.
Представим ситуацию: нам нужно в журнале документов закупки отобразить колонку с картинкой. Первым делом нам необходимо подготовить сам список — изменить его запрос и добавить элемент формы. Сделаем это в обработчике ПриСозданииНаСервере в расширении формы. Для изучения альтернативных подходов к добавлению полей можно использовать материал с методами доработки динамических списков.
Рассмотрим пример кода, в котором мы модифицируем текст запроса динамического списка, добавляя «пустое» поле. Иногда параллельно требуется вернуть кнопку "Связанные документы" на командную панель. Проанализируем ситуацию: нам нужно вставить поле в начало выборки SELECT.
&НаСервере
&После("ПриСозданииНаСервере")
Процедура РВ_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
// Модифицируем текст запроса списка
// Добавляем пустое строковое поле, которое будет служить контейнером для картинки
ТекстЗапроса = СписокДокументыЗакупки.ТекстЗапроса;
стрНачалоЗапроса = Сред(ТекстЗапроса, 1, 7); // "ВЫБРАТЬ"
стрНовСтрока = " """" КАК ПрисоединенныйФайл,";
стрОкончаниеЗапроса = Сред(ТекстЗапроса, 8);
СписокДокументыЗакупки.ТекстЗапроса = стрНачалоЗапроса + стрНовСтрока + стрОкончаниеЗапроса;
// Программное добавление элемента формы
НоваяКолонка = Элементы.Добавить("ПрисоединенныйФайл", Тип("ПолеФормы"), Элементы.СписокДокументыЗакупки);
НоваяКолонка.Вид = ВидПоляФормы.ПолеКартинки;
НоваяКолонка.ПутьКДанным = "СписокДокументыЗакупки.ПрисоединенныйФайл";
НоваяКолонка.Заголовок = "Файлы";
КонецПроцедуры
Важный нюанс: при программном изменении запроса убедитесь, что поле доступно для использования. Так же можно реализовать индикатор прогресса в ячейке списка — для этого удобно использовать компонент вывода настраиваемых индикаторов в формы списков. Для надежности можно программно установить свойство ИспользоватьВсегда для нового поля в компоновке данных списка.
Для заполнения созданной колонки используется событие ПриПолученииДанныхНаСервере. Это событие вызывается платформой при отрисовке строк списка на экране пользователя (например, при просмотре картинок-вложений в УНФ). Основная сложность заключается в том, что в расширениях этот метод часто вызывается с директивой &НаСервереБезКонтекста.
Разберем, почему это важно. Директива «Без контекста» означает, что нам недоступны реквизиты формы и её элементы напрямую через ЭтотОбъект или Элементы. Вся работа должна строиться исключительно на данных, переданных в параметрах процедуры.
Посмотрим на параметры процедуры ПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки):
ИмяЭлемента — строка, имя таблицы.Настройки — текущие настройки компоновки.Строки — это коллекция типа СтрокиДинамическогоСписка. Она ведет себя как Соответствие (Map), где ключом является ссылка на объект (или идентификатор строки), а значением — объект ДанныеСтрокиДинамическогоСписка.Многие разработчики совершают ошибку, пытаясь обратиться к данным строки через точку от ключа, например: строкаСписка.ПрисоединенныйФайл. Это не сработает, так как ключ — это просто ссылка (UUID или Ссылка на документ).
Выясним, как правильно обращаться к данным. Нам нужно получить значение из соответствия и обратиться к его свойству Данные. Ниже приведен пример реализации с учетом работы в расширении.
&НаСервереБезКонтекста
&После("СписокДокументыЗакупкиПриПолученииДанныхНаСервере")
Процедура РВ_СписокДокументыЗакупкиПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
// Получаем массив ключей (ссылок на документы), которые сейчас отображаются на экране
МассивСсылок = Строки.ПолучитьКлючи();
// В идеале здесь должен быть ОДИН запрос для получения информации о файлах для всех ссылок сразу
// Для примера просто покажем принцип обхода коллекции
Для Каждого КлЗн Из Строки Цикл
// КлЗн.Ключ - это Ссылка на документ
// КлЗн.Значение - это объект ДанныеСтрокиДинамическогоСписка
ДанныеСтроки = КлЗн.Значение.Данные;
// Проверяем тип, если журнал содержит разные документы
Если ТипЗнч(КлЗн.Ключ) = Тип("ДокументСсылка.ПриобретениеТоваровУслуг") Тогда
// Здесь должна быть логика проверки наличия файла
// Например, если файл есть, устанавливаем картинку
ДанныеСтроки.ПрисоединенныйФайл = БиблиотекаКартинок.Скрепка;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем критическую ошибку производительности. Если внутри цикла Для Каждого выполнять запрос к базе данных для каждой строки, то при прокрутке списка интерфейс будет «замирать». Если в списке 50 строк, система выполнит 50 маленьких запросов. Для отладки и поиска подобных проблем производительности пригодятся инструменты разработчика для оптимизации кода и запросов 1С.
Правильный алгоритм оптимизации:
Строки.ПолучитьКлючи() в массив.ПриобретениеТоваровУслугПрисоединенныеФайлы), используя условие ГДЕ ВладелецФайла В (&МассивСсылок).Строки просто получайте данные из подготовленного соответствия.Посмотрим, как это выглядит в коде:
// Внутри обработчика ПриПолученииДанныхНаСервере
МассивСсылок = Строки.ПолучитьКлючи();
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Файлы.ВладелецФайла КАК Владелец
|ИЗ
| Справочник.ПриобретениеТоваровУслугПрисоединенныеФайлы КАК Файлы
|ГДЕ
| Файлы.ВладелецФайла В(&МассивСсылок)";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
// Заполняем вспомогательное соответствие для быстрого поиска
ДокументыСФайлами = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ДокументыСФайлами.Вставить(Выборка.Владелец, Истина);
КонецЦикла;
// Теперь заполняем данные строк без обращений к БД
Для Каждого КлЗн Из Строки Цикл
Если ДокументыСФайлами[КлЗн.Ключ] <> Неопределено Тогда
КлЗн.Значение.Данные.ПрисоединенныйФайл = БиблиотекаКартинок.Скрепка;
КонецЕсли;
КонецЦикла;
Важно помнить, что поле формы с видом ПолеКартинки может работать в двух режимах:
Данные.ИмяПоля объект типа Картинка из библиотеки.КартинкиСтрок, то в данные нужно передавать Число — индекс картинки в этой коллекции. Это работает быстрее и предпочтительнее для больших списков.Рассмотрим ситуацию с БСП. В конфигурациях на базе БСП (как УТ 11.5) уже часто реализованы механизмы для отображения скрепок. Проверьте, нет ли в динамическом списке поля НаличиеФайлов. Если оно есть, достаточно просто вывести его на форму и настроить отображение картинки в свойствах элемента, не прибегая к сложному кодингу в ПриПолученииДанныхНаСервере.
Подводя итог, отметим, что использование расширений требует четкого понимания контекста выполнения. Метод ПриПолученииДанныхНаСервере является мощным инструментом для визуализации, но требует ответственного подхода к количеству запросов к базе данных, чтобы работа пользователя в журнале документов оставалась комфортной и быстрой.