Как настроить условное оформление табличной части по условию совпадения с другой табличной частью?

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

При разработке документов в управляемом интерфейсе 1С часто возникает задача визуального выделения строк одной таблицы на основе данных из другой таблицы. Например, требуется подсветить цветом строки в табличной части Товары, если комбинация полей Номенклатура, КодСтроки и Количество совпадает со строкой в табличной части ИспорченныеТовары.

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

Выясним причину: почему прямое сравнение таблиц в условном оформлении не работает

Проанализируем механику работы декларативного механизма УсловноеОформление управляемой формы:

  1. Контекст вычисления отбора: Условие оформления проверяется платформой построчно при отрисовке элементов конкретной таблицы. Полноценное соединение двух разных коллекций механизм формы выполнять не умеет. Если в качестве правого значения условия указать поле другой табличной части, система либо вообще не сможет разрешить путь к данным, либо использует данные только текущей активной строки второй таблицы.
  2. Отсутствие составных ключей в отборе: Механизм компоновки данных формы не позволяет сделать отбор по кортежу нескольких полей вида (Номенклатура, КодСтроки, Количество) В Списке. Даже передав список значений, можно проверить совпадение только одного поля, но не трех одновременно.
  3. Отсутствие событий построчной отрисовки: В управляемых формах нет обработчиков вроде ПриВыводеСтроки, которые применялись в обычном приложении. Единственный рабочий способ раскрасить таблицу — использовать коллекцию УсловноеОформление.

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

Шаг 1. Добавление реквизита формы и настройка условного оформления

Добавим в форму документа новый реквизит в подчинении первой табличной части — например, ЕстьСовпадение с типом Булево. Обратите внимание: реквизит создается только на форме и не сохраняется в структуре метаданных документа.

Далее настроим правило оформления. Настройку коллекции УсловноеОформление необходимо выполнять на сервере (например, в процедуре ПриСозданииНаСервере), так как на клиенте структура отборов доступна только для чтения.

Посмотрим на пример программной настройки оформления:


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

Важный нюанс: в условии отбора (ЛевоеЗначение) указывается полный путь к данным реквизита (Объект.Товары.ЕстьСовпадение), а в оформляемых полях (Поля.Элементы) — имя элемента интерфейса (колонки или всей таблицы формы).

Шаг 2. Реализация быстрой сверки табличных частей

Теперь необходимо обеспечить расчет и актуализацию значения ЕстьСовпадение. Рассмотрим два подхода к реализации сопоставления данных.

Вариант 1. Сверка на клиенте с использованием соответствия (быстрый способ без вызовов сервера)

Если объем строк в документе небольшой (до нескольких сотен строк), сверку целесообразно выполнять прямо на клиенте. Чтобы избежать квадратичной сложности $O(N \times M)$ при вложенных циклах, используем объект Соответствие и составной строковый ключ:


&НаКлиенте
Процедура АктуализироватьПодсветкуНаКлиенте()
    
    // Шаг 1. Формируем карту ключей из таблицы "ИспорченныеТовары"
    КартаИспорченных = Новый Соответствие;
    Для Каждого СтрИспорченные Из Объект.ИспорченныеТовары Цикл
        Ключ = Строка(СтрИспорченные.Номенклатура) + "|" 
             + Строка(СтрИспорченные.КодСтроки) + "|" 
             + Строка(СтрИспорченные.Количество);
        КартаИспорченных.Вставить(Ключ, Истина);
    КонецЦикла;
    
    // Шаг 2. Проверяем наличие ключа для каждой строки таблицы "Товары"
    Для Каждого СтрТовары Из Объект.Товары Цикл
        КлючТовара = Строка(СтрТовары.Номенклатура) + "|" 
                   + Строка(СтрТовары.КодСтроки) + "|" 
                   + Строка(СтрТовары.Количество);
        
        СтрТовары.ЕстьСовпадение = (КартаИспорченных[КлючТовара] <> Неопределено);
    КонецЦикла;
    
КонецПроцедуры

Такой алгоритм выполняется за $O(N + M)$, работает мгновенно и не создает сетевого трафика между клиентом и сервером.

Вариант 2. Сверка через запрос во временных таблицах (для больших таблиц)

Если в табличных частях содержатся тысячи строк, сопоставление эффективнее перенести в запрос с использованием конструкции ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Чтобы не передавать тяжелый контекст формы туда и обратно, вызов выносим в процедуру без контекста:


&НаСервереБезКонтекста
Функция ПолучитьНомераСтрокССовпадениями(ТаблицаТовары, ТаблицаИспорченные)
    
    Запрос = Новый Запрос;
    МенеджерВТ = Новый МенеджерВременныхТаблиц;
    Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
    
    Запрос.Текст = 
    "ВЫБРАТЬ
    |	ТТовары.НомерСтроки КАК НомерСтроки,
    |	ТТовары.Номенклатура КАК Номенклатура,
    |	ТТовары.КодСтроки КАК КодСтроки,
    |	ТТовары.Количество КАК Количество
    |ПОМЕСТИТЬ ВТ_Товары
    |ИЗ
    |	&ТаблицаТовары КАК ТТовары
    |;
    |ВЫБРАТЬ
    |	ТИспорченные.Номенклатура КАК Номенклатура,
    |	ТИспорченные.КодСтроки КАК КодСтроки,
    |	ТИспорченные.Количество КАК Количество
    |ПОМЕСТИТЬ ВТ_Испорченные
    |ИЗ
    |	&ТаблицаИспорченные КАК ТИспорченные
    |;
    |ВЫБРАТЬ РАЗЛИЧНЫЕ
    |	ВТ_Товары.НомерСтроки КАК НомерСтроки
    |ИЗ
    |	ВТ_Товары КАК ВТ_Товары
    |		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Испорченные КАК ВТ_Испорченные
    |		ПО ВТ_Товары.Номенклатура = ВТ_Испорченные.Номенклатура
    |			И ВТ_Товары.КодСтроки = ВТ_Испорченные.КодСтроки
    |			И ВТ_Товары.Количество = ВТ_Испорченные.Количество";
    
    Запрос.УстановитьПараметр("ТаблицаТовары", ТаблицаТовары);
    Запрос.УстановитьПараметр("ТаблицаИспорченные", ТаблицаИспорченные);
    
    Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("НомерСтроки");
    
КонецФункции

Шаг 3. Точки актуализации оформления при работе пользователя

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

  1. ПриЧтенииНаСервере и ПослеЗаписиНаСервере — для первоначального заполнения флага при загрузке и сохранении объекта;
  2. ПриОкончанииРедактирования и ПослеУдаления — в обработчиках обеих табличных частей (Товары и ИспорченныеТовары);
  3. ПриИзменении — для элементов формы, соответствующих колонкам Номенклатура, КодСтроки и Количество в обеих таблицах.

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

← На главную