При разработке интерфейсов на управляемых формах в 1С часто возникает задача сделать форму максимально интерактивной и интуитивно понятной для пользователя. Одним из таких сценариев является визуализация выбора цвета: когда пользователь выбирает определенный цвет в колонке таблицы, фон этой же ячейки (или всей строки) должен мгновенно окраситься в выбранный цвет.
Попытка решить эту задачу «в лоб» через механизм условного оформления (УО) программным путем часто приводит к тому, что код выполняется без ошибок, но визуально ничего не меняется. Давайте подробно разберем, почему так происходит, проанализируем внутреннее устройство платформы и найдем надежные способы обхода этого ограничения.
Рассмотрим типичный код, который часто пытаются использовать начинающие (и не только) разработчики в попытке привязать цвет оформления к значению в колонке таблицы:
// Этот код НЕ будет работать так, как ожидается:
Элемент_УО = УсловноеОформление.Элементы.Добавить();
Элемент_УО.Оформление.УстановитьЗначениеПараметра("ЦветФона", Новый ПолеКомпоновкиДанных("Объект.ТаблицаДанных.Цвет"));
Этот код успешно компилируется, платформа не выдает никаких предупреждений или исключений в процессе работы, однако ячейки таблицы остаются неокрашенными. Почему так происходит?
Дело в архитектурном ограничении механизма компоновки данных и условного оформления 1С. Параметры оформления (такие как ЦветФона, ЦветТекста, Шрифт, ВыделятьЖирным и др.) ожидают на вход конкретное, статическое значение соответствующего типа (в данном случае — объект типа Цвет).
Объект ПолеКомпоновкиДанных предназначен исключительно для адресации полей в левой части условий отбора (например, для сравнения поля таблицы с конкретным значением). Платформа 1С на текущий момент не умеет динамически «вычислять» значение цвета, извлекая его из базы данных или оперативной памяти для каждой строки «на лету» через адрес поля в параметрах оформления. Система видит тип ПолеКомпоновкиДанных там, где должен быть Цвет, и просто игнорирует данное правило оформления.
Для решения этой задачи нам потребуется применить обходные пути. Ниже мы разберем два наиболее эффективных решения в зависимости от типа таблицы на форме.
Если ваша таблица на форме является табличной частью документа/справочника или коллекцией типа ТаблицаЗначений, оптимальным решением будет динамическая генерация правил условного оформления под каждый уникальный цвет, выбранный пользователями.
Суть метода заключается в том, что вместо одного универсального (но неработающего) правила мы будем создавать множество правил — по одному на каждый уникальный цвет, который в данный момент присутствует в нашей таблице. Разберем этот процесс по шагам.
Нам потребуется написать процедуру на сервере, которая будет анализировать данные в таблице, собирать уникальные цвета и генерировать под них правила УО. Чтобы при повторных вызовах процедуры не затереть статичные настройки условного оформления, созданные в конфигураторе, мы будем помечать наши динамические правила специальным уникальным текстом в свойстве Представление.
Рассмотрим подробнее программную реализацию этой процедуры:
&НаСервере
Процедура ОбновитьДинамическоеУсловноеОформлениеНаСервере()
// 1. Очищаем старые динамические правила оформления, чтобы они не дублировались
Индекс = УсловноеОформление.Элементы.Количество() - 1;
Пока Индекс >= 0 Цикл
ЭлементУО = УсловноеОформление.Элементы[Индекс];
Если ЭлементУО.Представление = "ДинамическийЦветПоляВыбора" Тогда
УсловноеОформление.Элементы.Удалить(ЭлементУО);
КонецЕсли;
Индекс = Index - 1;
КонецЦикла;
// 2. Собираем уникальные цвета, которые сейчас выбраны в таблице.
// Используем Соответствие, чтобы исключить дублирование цветов и не плодить лишние правила.
УникальныеЦвета = Новый Соответствие;
Для Каждого СтрокаТаблицы Из Объект.ТаблицаДанных Цикл
Если ЗначениеЗаполнено(СтрокаТаблицы.Цвет) Тогда
УникальныеЦвета.Вставить(СтрокаТаблицы.Цвет, Истина);
КонецЕсли;
КонецЦикла;
// 3. Создаем отдельное правило условного оформления для каждого уникального цвета
Для Каждого КлючИЗначение Из УникальныеЦвета Цикл
ТекущийЦвет = КлючИЗначение.Ключ;
НовыйЭлементУО = УсловноеОформление.Элементы.Добавить();
НовыйЭлементУО.Представление = "ДинамическийЦветПоляВыбора";
НовыйЭлементУО.Использование = Истина;
// Задаем реальное значение цвета, которое мы получили из строки данных
НовыйЭлементУО.Оформление.УстановитьЗначениеПараметра("ЦветФона", ТекущийЦвет);
// Настраиваем отбор: красим строку только если значение в колонке "Цвет" равно текущему цвету правила
ЭлементОтбора = НовыйЭлементУО.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.ТаблицаДанных.Цвет");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = ТекущийЦвет;
ЭлементОтбора.Использование = Истина;
// Указываем оформляемое поле (колонку, которую нужно раскрасить)
ОформляемоеПоле = НовыйЭлементУО.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТаблицаДанныхЦвет");
ОформляемоеПоле.Использование = Истина;
КонецЦикла;
КонецПроцедуры
Чтобы условное оформление работало корректно в процессе взаимодействия пользователя с интерфейсом, нам необходимо вызывать созданную процедуру обновления в двух ключевых точках:
Посмотрим на пример подключения этих обработчиков событий:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Инициализируем оформление при открытии формы
ОбновитьДинамическоеУсловноеОформлениеНаСервере();
КонецПроцедуры
&НаКлиенте
Процедура ТаблицаДанныхЦветПриИзменении(Элемент)
// Сразу реагируем на выбор нового цвета пользователем
ОбновитьДинамическоеУсловноеОформлениеНаСервере();
КонецПроцедуры
Преимущества данного метода: Подход полностью универсален и работает на любых версиях платформы 1С 8.3, поддерживающих управляемые формы. Оформление применяется стандартными механизмами платформы.
Минусы метода: При изменении цвета происходит серверный вызов (контекстный или неконтекстный). Если в таблице будет содержаться огромное количество строк с сотнями разных уникальных цветов, это может привести к созданию слишком большого числа правил условного оформления, что теоретически способно замедлить отрисовку интерфейса.
Если ваша таблица на форме является не табличной частью, а Динамическим списком, то начиная с версии платформы 1С:Предприятие 8.3.20 у нас появился гораздо более элегантный, производительный и современный инструмент.
Разработчики платформы добавили для таблиц динамических списков клиентское событие ОбработкаОформленияДанных. Оно срабатывает непосредственно при выводе строк на экран монитора пользователя. Это позволяет обойтись без тяжеловесных серверных вызовов и настраивать цвета «на лету» прямо на стороне клиента.
Проанализируем ситуацию и посмотрим, как выглядит программная реализация этого механизма в модуле управляемой формы:
&НаКлиенте
Процедура СписокОбработкаОформленияДанных(Элемент, ОформлениеДанных)
// Обходим только те строки, которые видны пользователю в данный момент на экране
Для Каждого СтрокаОформления Из ОформлениеДанных Цикл
// Пытаемся получить значение цвета напрямую из данных текущей строки списка
ЦветСтроки = Неопределено;
Если СтрокаОформления.Данные.Свойство("Цвет", ЦветСтроки) Тогда
// Проверяем, что цвет действительно выбран и заполнен
Если ЗначениеЗаполнено(ЦветСтроки) Тогда
// Устанавливаем цвет фона непосредственно для ячейки "Цвет"
СтрокаОформления.Ячейки.Цвет.УстановитьЦветФона(ЦветСтроки);
// При необходимости, здесь же можно изменить цвет текста для читаемости:
// СтрокаОформления.Ячейки.Цвет.УстановитьЦветТекста(ПредопределенноеЗначение("ЦветаСтиля.ЦветЦветовогоВыделенияТекста"));
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важное примечание: Обратите внимание, что в событии ОбработкаОформленияДанных мы работаем исключительно на клиенте. Этот метод работает невероятно быстро, поскольку платформа передает в процедуру только видимую часть данных (порцию строк, которая отображается на экране), исключая необходимость перебирать всю базу данных.
При реализации динамического условного оформления разработчики часто совершают несколько типичных ошибок. Давайте разберем их, чтобы не допускать в своей практике:
"Объект.ТаблицаДанных.Цвет"). В то же время, при указании оформляемого поля в коллекции Поля условного оформления, имя поля должно соответствовать имени колонки в элементе формы таблицы (например, "ТаблицаДанныхЦвет").Использование = Истина. Если упустить эту деталь, правило просто не применится.УсловноеОформление.Элементы.Очистить() крайне нежелательно, если на форме уже настроены другие статические правила оформления в конфигураторе. Всегда используйте фильтрацию по свойству Представление, как показано в Решении 1.Таким образом, мы детально изучили, почему стандартная попытка передать поле компоновки в параметры оформления терпит неудачу, и освоили два мощных профессиональных инструмента для динамической раскраски интерфейсов 1С в зависимости от выбора пользователя.