Как настроить условное оформление в табличной части 1С по реквизиту номенклатуры?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет IT и автоматизация бизнеса
← На главную

В разработке на платформе 1С:Предприятие 8.3 часто возникает задача визуально выделить строки в табличной части документа при соблюдении определенных условий. Например, окрасить в другой цвет строки, где у выбранного товара (номенклатуры) не заполнен вес, объем или любой другой важный реквизит. На первый взгляд задача кажется простой, но при попытке обратиться к реквизитам номенклатуры «через точку» разработчики сталкиваются с тем, что оформление либо применяется ко всем строкам сразу, либо не работает вовсе.

В этой статье мы подробно разберем, почему возникает эта проблема, изучим особенности работы платформы с данными формы и реализуем оптимальное, быстрое решение, соответствующее стандартам разработки фирмы «1С».

Почему стандартный отбор «через точку» не работает в табличной части?

Выясним причину, почему код автора из первого сообщения темы на форуме окрашивал все строки без разбора. Автор пытался указать путь к данным в оформлении как Объект.Товары.ВесЧ.ВесЧислитель или использовать реквизит номенклатуры напрямую.

Для понимания этой проблемы разделим отображение данных в 1С на две категории:

  1. Динамические списки. Они работают напрямую с базой данных через SQL-запросы на сервере. Здесь платформа легко может разыменовать ссылку (пройти «через точку») и получить, например, значение Номенклатура.ВесЧислитель для условного оформления.
  2. Табличные части документов. Данные табличной части на клиенте представлены объектом типа ДанныеФормыКоллекция. Эти данные находятся в оперативной памяти клиентского компьютера. На клиенте нет кэша связанных объектов базы данных. Платформа физически не может «на лету» заглядывать внутрь ссылок справочников для каждой строки ТЧ без постоянных ресурсоемких обращений к серверу.

Попытка обратиться в условном оформлении к реквизиту через точку от ссылки в табличной части приводит к непредсказуемому поведению — отборы либо игнорируются, либо рассчитываются неверно. Единственное верное архитектурное решение в данном случае — создание вспомогательного реквизита формы в самой табличной части.

Архитектурное решение: Вспомогательный реквизит формы

Проанализируем стратегию решения. Чтобы условное оформление работало быстро и корректно, мы добавим в табличную часть формы дополнительную колонку (реквизит формы) с типом Булево (например, ВесЗаполнен). Эта колонка не будет сохраняться в базе данных, она нужна исключительно в оперативной памяти формы для управления визуальным отображением.

Схема работы будет выглядеть следующим образом:

  1. При открытии формы на сервере мы зачитываем веса для всех товаров в табличной части и заполняем наш реквизит ВесЗаполнен (значением Истина или Ложь).
  2. При изменении номенклатуры в строке мы оперативно обновляем это значение.
  3. В условном оформлении настраиваем простое правило: если ВесЗаполнен равен Ложь, то окрашиваем строку (или конкретную ячейку).

Рассмотрим по шагам реализацию этого механизма с акцентом на высокую производительность.

Шаг 1. Создание реквизита на форме

Выполним интерактивную настройку в конфигураторе:

  1. Откроем форму документа (например, «Заказ клиенту»).
  2. В правом верхнем окне «Реквизиты» найдем реквизит Объект и раскроем его табличную часть Товары.
  3. Нажмем правой кнопкой мыши по ветке Товары и выберем пункт Добавить колонку реквизита.
  4. Назовем новый реквизит ВесЗаполнен, укажем тип данных — Булево.

Обратите внимание: перетаскивать этот реквизит на саму форму (в дерево элементов слева) не обязательно, так как пользователю видеть эту колонку не нужно — она будет использоваться исключительно платформой для расчета оформления.

Шаг 2. Оптимальное заполнение при открытии формы (Борьба с N+1 запросами)

Нам необходимо заполнить созданную колонку при инициализации формы. В сообщениях форума предлагался простой перебор строк табличной части:


Для каждого ТекСтрока из Объект.Товары Цикл
    ТекСтрока.ВесЗаполнен = (ТекСтрока.Номенклатура.ВесЧислитель <> 0);
КонецЦикла;

Внимание! Это критическая ошибка производительности. Обращение к реквизиту через точку (ТекСтрока.Номенклатура.ВесЧислитель) внутри цикла заставляет систему делать отдельный запрос к базе данных на каждой итерации. Если в документе будет 150 строк, система сделает 150 микрозапросов к БД. Это значительно замедлит открытие формы.

Напишем правильный, оптимизированный код в обработчике ПриСозданииНаСервере, который получает все данные одним быстрым запросом с помощью методов БСП (Библиотеки Стандартных Подсистем):


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    ЗаполнитьПризнакВесаВТабличнойЧасти();
    НастроитьУсловноеОформлениеПрограммно();
    
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьПризнакВесаВТабличнойЧасти()
    
    // 1. Собираем только уникальные ссылки на номенклатуру из ТЧ, исключая пустые
    МассивНоменклатуры = Новый Массив;
    Для Каждого СтрокаТовары Из Объект.Товары Цикл
        Если ЗначениеЗаполнено(СтрокаТовары.Номенклатура) Тогда
            МассивНоменклатуры.Добавить(СтрокаТовары.Номенклатура);
        КонецЕсли;
    КонецЦикла;
    
    Если МассивНоменклатуры.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Удаляем дубликаты для уменьшения объема запроса
    ОбщегоНазначенияКлиентСервер.СвернутьМассив(МассивНоменклатуры);
    
    // 2. Одним запросом получаем веса для всех уникальных товаров
    ТаблицаВесов = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(МассивНоменклатуры, "ВесЧислитель");
    
    // 3. Быстро заполняем реквизит формы из кэшированной структуры данных
    Для Каждого СтрокаТовары Из Объект.Товары Цикл
        СвойстваНоменклатуры = ТаблицаВесов[СтрокаТовары.Номенклатура];
        Если СвойстваНоменклатуры <> Неопределено Тогда
            // Если вес равен нулю или не заполнен, записываем Ложь
            СтрокаТовары.ВесЗаполнен = (СвойстваНоменклатуры.ВесЧислитель <> 0);
        Иначе
            СтрокаТовары.ВесЗаполнен = Ложь;
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Шаг 3. Заполнение реквизита при изменении номенклатуры в строке

Когда пользователь интерактивно меняет товар в строке табличной части, нам нужно мгновенно пересчитывать наш флаг ВесЗаполнен. Нам понадобится обработчик события ПриИзменении для поля Номенклатура.

В процессе обсуждения на форуме возникла ошибка: Переменная не определена (ОбщегоНазначения) (Проверка: Тонкий клиент). Это произошло потому, что общий модуль ОбщегоНазначения является серверным, и обращаться к нему напрямую из клиентского метода нельзя. Нам нужно организовать быстрый серверный вызов. При этом критически важно использовать директиву &НаСервереБезКонтекста, чтобы не передавать на сервер и обратно тяжелое состояние всей формы.

Реализуем этот механизм:


&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
    
    СтрокаТаблицы = Элементы.Товары.ТекущиеДанные;
    Если СтрокаТаблицы = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Вызываем быстрый внеконтекстный серверный метод
    СтрокаТаблицы.ВесЗаполнен = ПолучитьСтатусЗаполненияВеса(СтрокаТаблицы.Номенклатура);
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьСтатусЗаполненияВеса(Знач СсылкаНоменклатуры)
    
    Если Не ЗначениеЗаполнено(СсылкаНоменклатуры) Тогда
        Возврат Ложь;
    КонецЕсли;
    
    // Чтение реквизита через БСП на сервере без контекста формы
    ВесЧислитель = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаНоменклатуры, "ВесЧислитель");
    
    Возврат (ВесЧислитель <> 0);
    
КонецФункции

Шаг 4. Настройка условного оформления (Программный метод)

Теперь, когда у нас есть надежно заполняемый признак ВесЗаполнен в каждой строке табличной части, мы можем настроить правила условного оформления. Напишем код для программного добавления элемента оформления.

Важный нюанс: при программном добавлении оформления всегда проверяйте, чтобы правила не дублировались, если процедура инициализации вызывается несколько раз в течение жизненного цикла формы.


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

Шаг 5. Альтернатива — Интерактивная настройка условного оформления

Если вы не хотите писать программный код для настройки УсловногоОформления, стандарты платформы 1С:Предприятие 8.3 позволяют сделать это визуально в конфигураторе. Это даже более предпочтительно, так как упрощает поддержку конфигурации другими разработчиками.

Рассмотрим по шагам интерактивную настройку:

  1. Откройте форму документа в Конфигураторе, перейдите на вкладку «Условное оформление» (в правом нижнем углу окна свойств формы).
  2. Нажмите кнопку Добавить.
  3. В появившемся окне на вкладке Оформление установите нужный параметр (например, «Цвет фона» — Выберите цвет из палитры Web-цветов).
  4. Перейдите на вкладку Условие и добавьте новый элемент отбора:
    • Поле: Объект.Товары.ВесЗаполнен
    • Вид сравнения: Равно
    • Правое значение: Ложь
  5. Перейдите на вкладку Оформляемые поля и добавьте поле табличной части, которое нужно выделить цветом (например, ТоварыНоменклатура или всю строку целиком).
  6. Нажмите ОК и сохраните конфигурацию.

Поскольку мы создали вспомогательный реквизит формы типа Булево, интерактивный конструктор условного оформления отработает быстро, надежно и без написания сложного программного кода.

Резюме совместной работы

Мы проанализировали частую проблему разработчиков при попытке обратиться к связанным данным реквизитов через точку в условном оформлении табличных частей документов. Мы выяснили, что из-за ограничений кэширования на клиенте такое оформление не может быть рассчитано платформой напрямую.

В ходе совместной работы мы успешно реализовали производительное и гибкое решение: добавили вспомогательный реквизит формы, оптимизировали серверное заполнение при открытии формы с защитой от множественных запросов к базе данных, корректно организовали контекстные вызовы и настроили правила условного оформления программным и интерактивным способами.

← На главную