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