В процессе разработки в среде 1С часто возникает задача визуального выделения определенных позиций в табличной части документа. Это может быть связано с необходимостью подсветить товары определенного бренда, позиции с особыми свойствами или номенклатуру, требующую внимания пользователя. В данной статье мы подробно разберем, как реализовать этот функционал для обычных форм (на примере «Управление торговлей 10.3»), избегая типичных ошибок новичков и проблем с производительностью.
Рассмотрим ситуацию: нам нужно выделить цветом строки в документе, содержащие определенную номенклатуру. Первое побуждение начинающего программиста — написать условие непосредственно по коду или артикулу:
Если ОформлениеСтроки.ДанныеСтроки.Номенклатура.Код = "0000123" Тогда
ОформлениеСтроки.Ячейки.Номенклатура.ЦветФона = WebЦвета.Зеленый;
КонецЕсли;
Проанализируем этот подход. Если таких позиций 30 или 100, код превратится в «простыню» из условий Если...ИначеЕсли. Кроме того, любое изменение списка номенклатуры потребует вмешательства программиста. Поэтому мы выберем более гибкий путь: будем хранить признак цвета в свойствах номенклатуры (через штатный механизм дополнительных реквизитов) и использовать его для раскраски.
Прежде чем писать код, необходимо создать аналитику. В типовых конфигурациях на обычных формах (УТ 10, УПП 1.3) уже есть регистр сведений ЗначенияСвойствОбъектов. Разберем порядок действий:
Теперь наша задача — научить программу «видеть» этот признак при отрисовке таблицы.
Событие ПриВыводеСтроки вызывается для каждой строки табличного поля в момент её отображения. Это самый простой способ, подходящий для небольших документов.
Рассмотрим пример кода, который мы разместим в модуле формы документа:
Процедура ТоварыПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Подготовим запрос для получения свойства конкретной номенклатуры
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗначенияСвойствОбъектов.Значение КАК ЗначениеСвойства
|ИЗ
| РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
|ГДЕ
| ЗначенияСвойствОбъектов.Объект = &Номенклатура
| И ЗначенияСвойствОбъектов.Свойство.Наименование = ""ЦветСтроки""";
Запрос.УстановитьПараметр("Номенклатура", ДанныеСтроки.Номенклатура);
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
// Если значение свойства соответствует нашему эталону, красим ячейку
Если Выборка.ЗначениеСвойства.Наименование = "ВесеннеЗеленый" Тогда
ОформлениеСтроки.Ячейки.Номенклатура.ЦветФона = WebЦвета.ВесеннеЗеленый;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важное предостережение: выполнение запроса внутри события ПриВыводеСтроки — это «плохой тон» в программировании 1С. Если в документе будет много строк, при прокрутке списка 1С будет выполнять запрос для каждой новой строки на экране, что вызовет заметные тормоза интерфейса.
Выясним причину, почему запросы к свойствам могут работать медленно. В регистре ЗначенияСвойствОбъектов измерение Объект имеет составной тип данных (это может быть и Номенклатура, и Контрагент, и Документ). Когда мы пишем в запросе ЗначенияСвойствОбъектов.Объект.Наименование, платформа выполняет соединение (JOIN) со всеми возможными таблицами, входящими в составной тип. Это критически замедляет работу.
Правильный подход к написанию запроса:
ССЫЛКА.Проанализируем оптимизированный фрагмент условия в запросе:
ГДЕ
ЗначенияСвойствОбъектов.Объект = &Номенклатура
И ЗначенияСвойствОбъектов.Свойство = &НужноеСвойство
Чтобы интерфейс работал «летаючи», используем событие ПриПолученииДанных. Оно отличается тем, что вызывается сразу для всей пачки строк (коллекции ОформленияСтрок), которые система планирует отрисовать в данный момент. Это позволяет нам выполнить всего один запрос вместо десятков.
Рассмотрим алгоритм реализации:
Процедура ТоварыПриПолученииДанных(Элемент, ОформленияСтрок)
// 1. Соберем всю номенклатуру из видимых строк в массив
МассивНоменклатуры = Новый Массив;
СоответствиеОформления = Новый Соответствие;
Для Каждого Оформление Из ОформленияСтрок Цикл
// Проверяем, что в строке есть данные и номенклатура заполнена
Если Оформление.ДанныеСтроки = Неопределено Тогда Продолжить; КонецЕсли;
ТекНоменклатура = Оформление.ДанныеСтроки.Номенклатура;
МассивНоменклатуры.Добавить(ТекНоменклатура);
// Запоминаем связь: какая номенклатура какому оформлению строки соответствует
СоответствиеОформления.Вставить(ТекНоменклатура, Оформление);
КонецЦикла;
// 2. Одним запросом получаем свойства для всего списка номенклатуры
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗначенияСвойствОбъектов.Объект КАК Номенклатура
|ИЗ
| РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
|ГДЕ
| ЗначенияСвойствОбъектов.Объект В(&МассивНоменклатуры)
| И ЗначенияСвойствОбъектов.Свойство = &СвойствоЦвет
| И ЗначенияСвойствОбъектов.Значение = &ЗначениеВесеннеЗеленый";
// Параметры СвойствоЦвет и ЗначениеВесеннеЗеленый лучше найти один раз при открытии формы
Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
Запрос.УстановитьПараметр("СвойствоЦвет", СтруктураНастроек.СвойствоЦвет);
Запрос.УстановитьПараметр("ЗначениеВесеннеЗеленый", СтруктураНастроек.ЗначениеЦвета);
Выборка = Запрос.Выполнить().Выбрать();
// 3. Раскрашиваем только те строки, которые попали в результат запроса
Пока Выборка.Следующий() Цикл
ОформлениеСтроки = СоответствиеОформления.Получить(Выборка.Номенклатура);
Если ОформлениеСтроки <> Неопределено Тогда
ОформлениеСтроки.Ячейки.Номенклатура.ЦветФона = WebЦвета.ВесеннеЗеленый;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Для достижения максимальной производительности в высоконагруженных системах (например, если в справочнике миллионы позиций), мы рекомендуем использовать **кэширование списка раскраски**. Рассмотрим, как это сделать:
СписокОсобойНоменклатуры (тип Соответствие).ПередОткрытием или ПриОткрытии один раз выполним запрос ко всему регистру свойств, отобрав номенклатуру с нужным цветом.Соответствие, где ключом будет ссылка на номенклатуру, а значением — Истина.ПриВыводеСтроки будем делать просто:
Если СписокОсобойНоменклатуры.Получить(ДанныеСтроки.Номенклатура) <> Неопределено Тогда
ОформлениеСтроки.Ячейки.Номенклатура.ЦветФона = WebЦвета.Зеленый;
КонецЕсли;
Этот метод полностью исключает запросы к базе данных во время отрисовки интерфейса, так как данные уже лежат в оперативной памяти компьютера пользователя.
Проанализировав ситуацию, мы выяснили, что наиболее эффективный способ раскраски ТЧ в обычных формах 1С — это использование события ПриПолученииДанных с пакетным запросом или кэширование списка во внутреннем соответствии формы. Это обеспечивает отличную отзывчивость программы даже при работе с большими документами и обширными базами данных. Помните о «проблеме точек» в запросах к составным типам и всегда старайтесь выносить поиск параметров (свойств, значений) за пределы циклов отрисовки.