При разработке документов в управляемом интерфейсе 1С часто возникает задача визуального выделения строк одной таблицы на основе данных из другой таблицы. Например, требуется подсветить цветом строки в табличной части Товары, если комбинация полей Номенклатура, КодСтроки и Количество совпадает со строкой в табличной части ИспорченныеТовары.
Попытка настроить такое правило «в лоб» через стандартный интерфейс условного оформления или прямое сравнение реквизитов двух таблиц в коде не дает результата. Разберем по шагам, почему возникает эта проблема и как правильно реализовать подобную логику.
Проанализируем механику работы декларативного механизма УсловноеОформление управляемой формы:
(Номенклатура, КодСтроки, Количество) В Списке. Даже передав список значений, можно проверить совпадение только одного поля, но не трех одновременно.ПриВыводеСтроки, которые применялись в обычном приложении. Единственный рабочий способ раскрасить таблицу — использовать коллекцию УсловноеОформление.Единственное надежное архитектурное решение в таком сценарии — добавить в первую табличную часть специальный дополнительный реквизит формы (флаг совпадения типа Булево), рассчитывать его программно при изменении данных, а само условное оформление привязать к этому флагу.
Добавим в форму документа новый реквизит в подчинении первой табличной части — например, ЕстьСовпадение с типом Булево. Обратите внимание: реквизит создается только на форме и не сохраняется в структуре метаданных документа.
Далее настроим правило оформления. Настройку коллекции УсловноеОформление необходимо выполнять на сервере (например, в процедуре ПриСозданииНаСервере), так как на клиенте структура отборов доступна только для чтения.
Посмотрим на пример программной настройки оформления:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Создаем новый элемент условного оформления формы
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
// 1. Указываем оформляемые поля (имя элемента формы колонок или таблицы)
ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("Товары");
// 2. Задаем условие: флаг ЕстьСовпадение = Истина
ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.ЕстьСовпадение");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = Истина;
ЭлементОтбора.Использование = Истина;
// 3. Задаем визуальное оформление (например, цвет фона)
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.СветлоРозовый);
КонецПроцедуры
Важный нюанс: в условии отбора (ЛевоеЗначение) указывается полный путь к данным реквизита (Объект.Товары.ЕстьСовпадение), а в оформляемых полях (Поля.Элементы) — имя элемента интерфейса (колонки или всей таблицы формы).
Теперь необходимо обеспечить расчет и актуализацию значения ЕстьСовпадение. Рассмотрим два подхода к реализации сопоставления данных.
Если объем строк в документе небольшой (до нескольких сотен строк), сверку целесообразно выполнять прямо на клиенте. Чтобы избежать квадратичной сложности $O(N \times M)$ при вложенных циклах, используем объект Соответствие и составной строковый ключ:
&НаКлиенте
Процедура АктуализироватьПодсветкуНаКлиенте()
// Шаг 1. Формируем карту ключей из таблицы "ИспорченныеТовары"
КартаИспорченных = Новый Соответствие;
Для Каждого СтрИспорченные Из Объект.ИспорченныеТовары Цикл
Ключ = Строка(СтрИспорченные.Номенклатура) + "|"
+ Строка(СтрИспорченные.КодСтроки) + "|"
+ Строка(СтрИспорченные.Количество);
КартаИспорченных.Вставить(Ключ, Истина);
КонецЦикла;
// Шаг 2. Проверяем наличие ключа для каждой строки таблицы "Товары"
Для Каждого СтрТовары Из Объект.Товары Цикл
КлючТовара = Строка(СтрТовары.Номенклатура) + "|"
+ Строка(СтрТовары.КодСтроки) + "|"
+ Строка(СтрТовары.Количество);
СтрТовары.ЕстьСовпадение = (КартаИспорченных[КлючТовара] <> Неопределено);
КонецЦикла;
КонецПроцедуры
Такой алгоритм выполняется за $O(N + M)$, работает мгновенно и не создает сетевого трафика между клиентом и сервером.
Если в табличных частях содержатся тысячи строк, сопоставление эффективнее перенести в запрос с использованием конструкции ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Чтобы не передавать тяжелый контекст формы туда и обратно, вызов выносим в процедуру без контекста:
&НаСервереБезКонтекста
Функция ПолучитьНомераСтрокССовпадениями(ТаблицаТовары, ТаблицаИспорченные)
Запрос = Новый Запрос;
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст =
"ВЫБРАТЬ
| ТТовары.НомерСтроки КАК НомерСтроки,
| ТТовары.Номенклатура КАК Номенклатура,
| ТТовары.КодСтроки КАК КодСтроки,
| ТТовары.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Товары
|ИЗ
| &ТаблицаТовары КАК ТТовары
|;
|ВЫБРАТЬ
| ТИспорченные.Номенклатура КАК Номенклатура,
| ТИспорченные.КодСтроки КАК КодСтроки,
| ТИспорченные.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Испорченные
|ИЗ
| &ТаблицаИспорченные КАК ТИспорченные
|;
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| ВТ_Товары.НомерСтроки КАК НомерСтроки
|ИЗ
| ВТ_Товары КАК ВТ_Товары
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Испорченные КАК ВТ_Испорченные
| ПО ВТ_Товары.Номенклатура = ВТ_Испорченные.Номенклатура
| И ВТ_Товары.КодСтроки = ВТ_Испорченные.КодСтроки
| И ВТ_Товары.Количество = ВТ_Испорченные.Количество";
Запрос.УстановитьПараметр("ТаблицаТовары", ТаблицаТовары);
Запрос.УстановитьПараметр("ТаблицаИспорченные", ТаблицаИспорченные);
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("НомерСтроки");
КонецФункции
Чтобы подсветка строк оставалась актуальной при добавлении, редактировании или удалении данных пользователем, процедуру обновления флага необходимо вызывать в ключевых событиях формы:
ПриЧтенииНаСервере и ПослеЗаписиНаСервере — для первоначального заполнения флага при загрузке и сохранении объекта;ПриОкончанииРедактирования и ПослеУдаления — в обработчиках обеих табличных частей (Товары и ИспорченныеТовары);ПриИзменении — для элементов формы, соответствующих колонкам Номенклатура, КодСтроки и Количество в обеих таблицах.Использование дополнительного клиентского реквизита формы в сочетании со стандартным условным оформлением полностью снимает ограничения платформы и обеспечивает корректную подсветку строк по сложным составным критериям.