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