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