При разработке интерфейсов на управляемых формах часто возникает задача визуального контроля данных: необходимо сопоставить две колонки табличной части и выделить цветом ячейки, если расхождение между ними превышает допустимую погрешность (дельту). Однако попытка настроить такое условие напрямую в механизме условного оформления формы приводит к ошибкам. Разберем, почему возникает эта проблема и как ее правильно решить на практике.
Рассмотрим типовую попытку разработчика задать вычисляемый интервал программно:
ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.ДанныеФайла.ЗПБаза");
ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Больше;
ОтборЭлемента.ПравоеЗначение = Новый ПолеКомпоновкиДанных("Объект.ДанныеФайла.ЗПФайл") + Объект.ТочностьПроверки;
При выполнении такого кода платформа 1С аварийно завершает работу с ошибкой: «невозможно преобразование к числу». Выясним причину такого поведения платформы:
ПолеКомпоновкиДанных не содержит фактического числового значения строки, это всего лишь объектная ссылка на путь к данным (строковый идентификатор реквизита). В платформе 1С для данного типа не перегружены математические операторы плюс и минус. Попытка сложить ПолеКомпоновкиДанных с числом расценивается платформой как попытка сложения несовместимых типов.ПравоеЗначение элемента отбора может находиться либо конкретное фиксированное значение (число, строка, дата), либо одиночное поле данных через Новый ПолеКомпоновкиДанных(...) без каких-либо математических операций.Если проверяемых колонок немного (одна или две пары), классическим решением является добавление в табличную часть вычисляемого служебного реквизита с типом Булево (например, ЗПБаза_Ошибка).
Разберем по шагам реализацию этого подхода:
ОшибкаРасхождения (тип Булево). Не обязательно сохранять его в базе данных, если таблица формируется только для интерактивной обработки.ПриСозданииНаСервере):
Элемент = УсловноеОформление.Элементы.Добавить();
ПолеЭлемента = Элемент.Поля.Элементы.Добавить();
ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных("ДанныеФайлаЗПБаза");
ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.ДанныеФайла.ОшибкаРасхождения");
ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ОтборЭлемента.ПравоеЗначение = Истина;
Элемент.Оформление.УстановитьЗначениеПараметра("ЦветТекста", WebЦвета.Красный);
&НаКлиенте
Процедура ПересчитатьОшибкиВСтроке(СтрокаТЧ)
Погрешность = Объект.ТочностьПроверки;
Разница = СтрокаТЧ.ЗПБаза - СтрокаТЧ.ЗПФайл;
Если Разница < 0 Тогда
Разница = -Разница;
КонецЕсли;
СтрокаТЧ.ОшибкаРасхождения = (Разница > Погрешность);
КонецПроцедуры
Эту процедуру достаточно вызывать в событиях ПриИзменении для полей ЗПБаза, ЗПФайл, а также при изменении поля погрешности в шапке (в цикле по всей табличной части).
Что делать, если в таблице проверяется 20 пар колонок или более? Создавать 20–40 служебных колонок типа Булево крайне неудобно и загромождает структуру данных. Рассмотрим более элегантный и универсальный способ — использование одной строковой колонки-маски.
Разберем по шагам внедрение маски расхождений:
ОшибочныеКолонки (тип Строка, переменной длины).ПриСозданииНаСервере настроим условное оформление для каждой проверяемой колонки через вид сравнения Содержит:
&НаСервере
Процедура НастроитьОформлениеДляКолонки(ИмяКолонки)
Элемент = УсловноеОформление.Элементы.Добавить();
ПолеЭлемента = Элемент.Поля.Элементы.Добавить();
ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(ИмяКолонки);
ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.ДанныеФайла.ОшибочныеКолонки");
ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Содержит;
ОтборЭлемента.ПравоеЗначение = ";" + ИмяКолонки + ";";
Элемент.Оформление.УстановитьЗначениеПараметра("ЦветТекста", WebЦвета.Красный);
КонецПроцедуры
Такую процедуру можно легко вызвать в цикле по списку проверяемых имен колонок.
&НаКлиенте
Процедура ПроверитьСтрокуТаблицы(СтрокаТЧ)
Погрешность = Объект.ТочностьПроверки;
МаскаОшибок = ";";
// Проверка первой пары
Если Не ВходитВИнтервал(СтрокаТЧ.Колонка1, СтрокаТЧ.Колонка2, Погрешность) Тогда
МаскаОшибок = МаскаОшибок + "Колонка1;";
КонецЕсли;
// Проверка второй пары
Если Не ВходитВИнтервал(СтрокаТЧ.Колонка3, СтрокаТЧ.Колонка4, Погрешность) Тогда
МаскаОшибок = МаскаОшибок + "Колонка3;";
КонецЕсли;
// Применяем результат к служебному реквизиту строки
СтрокаТЧ.ОшибочныеКолонки = МаскаОшибок;
КонецПроцедуры
&НаКлиенте
Функция ВходитВИнтервал(Значение1, Значение2, Погрешность)
Дельта = Значение1 - Значение2;
Если Дельта < 0 Тогда
Дельта = -Дельта;
КонецЕсли;
Возврат (Дельта <= Погрешность);
КонецФункции
Использование разделителей (символа точки с запятой) в начале, конце и между именами колонок гарантирует точное совпадение при поиске подстроки через Содержит и исключает ложные срабатывания, если имена колонок похожи (например, Колонка1 и Колонка10).
Таким образом, мы обходим платформенное ограничение механизма условного оформления, сохраняем высокую производительность формы за счет клиентских вычислений и не перегружаем структуру метаданных десятками служебных полей.