При работе с 1С часто возникает задача визуально выделить определенные строки в табличных частях документов или форм, чтобы акцентировать внимание пользователя на важных данных. Одним из наиболее гибких и мощных инструментов для этого является механизм УсловноеОформление. Однако его программная настройка, особенно в расширениях типовых конфигураций, может вызывать сложности, связанные с порядком выполнения кода, очисткой настроек и корректным указанием путей к данным. В этом руководстве мы подробно разберем, как эффективно применять программное условное оформление, рассмотрим типичные проблемы и предложим надежные решения.
Прежде чем перейти к решению, давайте проанализируем основные моменты, которые могут привести к некорректной работе условного оформления.
Определение проблемы и первоначальный код:
Наш коллега столкнулся с проблемой, когда написанный им код для условного оформления строк табличной части не работал, хотя отладчик показывал, что все настройки применялись. Изначально код выглядел следующим образом:
&НаСервере
Процедура ГАФ_ПриЧтенииНаСервереПосле(ТекущийОбъект)
МассивИменКолонокДляПодсветки = Новый Массив;
Для каждого Стр из Элементы.Товары.ПодчиненныеЭлементы Цикл
МассивИменКолонокДляПодсветки.Добавить(Стр.Имя);
КонецЦикла;
ЭлементОформления = УсловноеОформление.Элементы.Добавить;
ЭлементОформления.Использование = Истина;
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", Новый Цвет(204, 255, 204));
ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.СегментНоменклатуры.Родитель.Наименование");
ЭлементУсловия.ПравоеЗначение = "Сегменты по ликвидности";
ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементУсловия.Использование = Истина;
Для каждого ТекЭлемент из МассивИменКолонокДляПодсветки Цикл
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить;
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(ТекЭлемент);
КонецЦикла;
КонецПроцедуры
Несмотря на кажущуюся логичность, оформление не применялось. Это заставляет нас углубиться в нюансы взаимодействия нашего кода с типовой конфигурацией.
Проблема очистки УсловногоОформления в типовых решениях:
Одной из наиболее частых причин "неработающего" условного оформления является то, что типовая конфигурация может очищать или переопределять настройки оформления. Это происходит, например, в обработчике события формы ПриСозданииНаСервере. Если ваш код, устанавливающий условное оформление, выполняется до того, как типовой код очистит или переопределит его, ваши настройки будут потеряны. Вы можете обнаружить в стандартных модулях подобные строки:
УсловноеОформление.Элементы.Очистить();
// или
// УстановитьУсловноеОформление(); // где эта процедура переопределяет все
Такая очистка удаляет все ранее заданные элементы условного оформления, будь то созданные в конфигураторе или программно.
Важность порядка выполнения кода и директива &После:
Чтобы гарантировать, что ваше программное условное оформление не будет стерто типовыми механизмами, критически важно, чтобы ваш код выполнялся *после* всех стандартных процедур инициализации формы. При работе с расширениями для этого служит директива &После. Размещая вашу процедуру с этой директивой, вы указываете системе выполнить ее только после завершения выполнения одноименной процедуры основного модуля или других расширений.
Например, если вы хотите установить условное оформление после того, как все типовые процедуры ПриСозданииНаСервере отработали, вы должны использовать:
&НаСервере
&После("ПриСозданииНаСервере")
Процедура Моя_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Ваш код УсловногоОформления здесь
КонецПроцедуры
Это обеспечивает, что ваш код будет последним, кто внесет изменения в коллекцию УсловноеОформление, и ваши настройки не будут перезаписаны.
Один из самых надежных и часто используемых подходов в типовых конфигурациях для сложного условного оформления — это создание вспомогательного реквизита в табличной части и использование его в условии. Этот метод позволяет вынести сложную логику определения условия в отдельную процедуру и значительно упростить само условное оформление.
Шаг 1: Добавление вспомогательного реквизита
Мы добавляем новый реквизит в табличную часть формы, например, с именем НужноВыделитьСтроку и типом Булево. Этот реквизит должен быть невидим для пользователя (свойство "Видимость" в false) и не сохраняться в базу данных, если он является только для целей оформления.
Шаг 2: Заполнение вспомогательного реквизита
В одной из серверных процедур формы, которая выполняется после загрузки данных в табличную часть (например, в той же ПриСозданииНаСервере или ПриЧтенииНаСервереПосле, но с учетом порядка выполнения), мы заполняем этот булевый реквизит. Здесь мы реализуем всю нашу сложную логику проверки условия. Критически важно убедиться, что этот реквизит действительно заполняется! Это была одна из основных проблем, с которой столкнулся автор темы, несмотря на все остальные правильные настройки.
Пример процедуры заполнения (размещаем ее так, чтобы она вызывалась после загрузки данных):
&НаСервере
Процедура ЗаполнитьВспомогательныеРеквизитыТоваров()
Для каждого СтрокаТовара из Объект.Товары Цикл
// Здесь размещаем нашу логику
Если СтрокаТовара.СегментНоменклатуры.Родитель.Наименование = "Сегменты по ликвидности" Тогда
СтрокаТовара.НужноВыделитьСтроку = Истина;
Иначе
СтрокаТовара.НужноВыделитьСтроку = Ложь;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
И вызов этой процедуры из ПриСозданииНаСервере или ПриЧтенииНаСервереПосле (с учетом директивы &После в расширении):
&НаСервере
&После("ПриСозданииНаСервере") // Или &После("ПриЧтенииНаСервереПосле") если данные заполняются там
Процедура Моя_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЗаполнитьВспомогательныеРеквизитыТоваров();
// ... далее код по установке УсловногоОформления
КонецПроцедуры
Шаг 3: Настройка УсловногоОформления с новым реквизитом
Теперь, когда у нас есть простой булевый флаг, мы можем настроить условное оформление, используя его в качестве условия. Это значительно упрощает логику в самом УО.
// Этот код размещаем в той же Моя_ПриСозданииНаСервере после вызова ЗаполнитьВспомогательныеРеквизитыТоваров()
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
ЭлементОформления.Использование = Истина;
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", Новый Цвет(204, 255, 204)); // Светло-зеленый
// Условие отбора теперь очень простое
ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.НужноВыделитьСтроку"); // Путь к нашему новому реквизиту
ЭлементУсловия.ПравоеЗначение = Истина;
ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементУсловия.Использование = Истина;
// Оформляемые поля - вся строка табличной части
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("Товары"); // Оформляем всю табличную часть "Товары"
Обратите внимание, что для оформления всей строки достаточно указать имя табличной части (например, "Товары") в ПолеКомпоновкиДанных, а не перечислять все колонки по отдельности. Однако, если вам нужно оформить только конкретные колонки, тогда следует перечислить их имена.
Если мы хотим избежать создания вспомогательного реквизита, мы можем попытаться настроить условное оформление напрямую, но с обязательным учетом всех вышеупомянутых нюансов.
Шаг 1: Гарантируем корректное выполнение кода
Как уже говорилось, размещаем наш код в расширении с директивой &После для процедуры ПриСозданииНаСервере. Это самый надежный способ:
&НаСервере
&После("ПриСозданииНаСервере")
Процедура Моя_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// ... сюда помещаем весь код УсловногоОформления
КонецПроцедуры
Если в вашем конкретном случае данные для условия заполняются позже, возможно, вам придется использовать &После("ПриЧтенииНаСервереПосле") или аналогичную процедуру, где данные табличной части гарантированно заполнены.
Шаг 2: Создание элемента УсловногоОформления
Создаем новый элемент оформления и устанавливаем параметры фона:
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
ЭлементОформления.Использование = Истина;
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", Новый Цвет(204, 255, 204)); // Светло-зеленый
Мы не используем УсловноеОформление.Элементы.Очистить(), чтобы не удалить настройки, которые могли быть сделаны в конфигураторе или другими расширениями, если только это не является нашей явной целью.
Шаг 3: Определение условий отбора
Правильно указываем путь к данным в условии. Для реквизитов табличной части, принадлежащих объекту формы, путь должен начинаться с "Объект.ИмяТабличнойЧасти.ИмяРеквизита".
ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.СегментНоменклатуры.Родитель.Наименование");
ЭлементУсловия.ПравоеЗначение = "Сегменты по ликвидности";
ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементУсловия.Использование = Истина;
Здесь "Объект.Товары.СегментНоменклатуры.Родитель.Наименование" указывает на реквизит Наименование родителя сегмента номенклатуры в табличной части Товары, которая, в свою очередь, является частью основного объекта формы.
Шаг 4: Указание оформляемых полей
Для оформления всей строки табличной части указываем имя табличной части:
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("Товары"); // Оформляем всю табличную часть "Товары"
Если необходимо оформить только определенные колонки, их имена нужно перечислить в коллекции Поля.Элементы:
// Пример для оформления только колонки "Номенклатура" и "Количество"
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТоварыНоменклатура"); // Имя колонки в форме
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТоварыКоличество"); // Имя колонки в форме
Имя поля здесь соответствует имени элемента формы (колонки табличной части), а не имени реквизита объекта.
Рассмотрим полный пример кода, который демонстрирует создание условного оформления. Этот пример адаптирован из обсуждения и включает основные принципы, необходимые для успешной работы. Предполагаем, что этот код вызывается в расширении с директивой &После, например, для ПриСозданииНаСервере.
&НаСервере
&После("ПриСозданииНаСервере") // Гарантируем выполнение после типовой логики
Процедура ГАФ_УстановитьУсловноеОформлениеТоваров(Отказ, СтандартнаяОбработка)
// Если требуется полностью переопределить все УО, раскомментируйте следующую строку.
// В большинстве случаев это нежелательно в расширениях.
// УсловноеОформление.Элементы.Очистить();
// 1. Создаем новый элемент условного оформления
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
ЭлементОформления.Использование = Истина;
// 2. Устанавливаем параметры оформления (цвет фона)
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", Новый Цвет(204, 255, 204)); // Светло-зеленый цвет
// 3. Определяем условие отбора
// В данном случае, используем вспомогательный булевый реквизит "НужноВыделитьСтроку"
// или исходное сложное условие.
// Предполагаем, что реквизит "НужноВыделитьСтроку" уже заполнен,
// например, в отдельной процедуре, вызванной ранее в этом же обработчике &После.
// Пример с булевым реквизитом:
ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.НужноВыделитьСтроку");
ЭлементУсловия.ПравоеЗначение = Истина;
ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементУсловия.Использование = Истина;
// Пример с исходным сложным условием (если нет вспомогательного реквизита):
// ЭлементУсловия = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
// ЭлементУсловия.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.СегментНоменклатуры.Родитель.Наименование");
// ЭлементУсловия.ПравоеЗначение = "Сегменты по ликвидности";
// ЭлементУсловия.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
// ЭлементУсловия.Использование = Истина;
// 4. Указываем оформляемые поля
// Для оформления всей строки табличной части "Товары"
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("Товары"); // Имя элемента формы - табличной части
// Если бы мы хотели оформить только конкретные колонки, то:
// ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
// ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТоварыНоменклатура"); // Имя колонки в форме
// ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
// ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТоварыКоличество"); // Имя колонки в форме
КонецПроцедуры
В этом примере мы предпочли использовать булевый реквизит, так как это более гибкий и часто встречающийся подход. Не забывайте о необходимости вызова процедуры, которая заполняет НужноВыделитьСтроку, перед этим кодом.
Подводя итоги, мы можем выделить несколько ключевых моментов для успешного программного применения условного оформления:
Порядок выполнения кода: Всегда убеждайтесь, что ваш код условного оформления выполняется *после* всех типовых механизмов инициализации формы, особенно если работаете в расширении. Используйте директиву &После для этого.
Вспомогательные реквизиты: Не стесняйтесь использовать вспомогательные булевы реквизиты в табличной части. Это не "костыль", а адекватная подготовка данных, которая упрощает логику условного оформления и может повысить производительность, так как сложное условие вычисляется однократно при загрузке данных.
Проверка заполнения данных: Если вы используете вспомогательные реквизиты, обязательно убедитесь, что они действительно заполняются. Как показал опыт автора, иногда именно этот, казалось бы, очевидный момент становится причиной неработоспособности.
Пути к данным: Внимательно проверяйте пути к данным в ПолеКомпоновкиДанных. Для реквизитов объекта формы используйте "Объект.ИмяТабличнойЧасти.ИмяРеквизита". Для указания оформляемых полей всей строки табличной части достаточно указать имя самой табличной части (например, "Товары").
Очистка оформления: Помните, что метод УсловноеОформление.Элементы.Очистить() полностью удаляет все настройки. Используйте его с осторожностью и только если вы действительно хотите переопределить все существующее условное оформление. В большинстве случаев в расширениях достаточно просто добавить новые элементы оформления.
Следуя этим рекомендациям, вы сможете эффективно использовать программное условное оформление для решения самых разнообразных задач визуализации данных в 1С.