При разработке управляемых форм часто возникает задача уведомить пользователя об ошибке в конкретной ячейке табличной части. Для ссылочных объектов конфигурации (документов, справочников) обычно заполняется свойство КлючДанных, куда передается ссылка на объект. Однако у встроенных и внешних обработок ссылки в базе данных нет. При попытке вывести оповещение разработчики сталкиваются с тем, что сообщение об ошибке позиционируется не на конкретную строку, а привязывается ко всей табличной части в целом.
Разберем подробно, почему возникает такое поведение платформы и как правильно связать сообщение с конкретной строкой и реквизитом табличной части обработки.
Проанализируем ключевые особенности механизма СообщениеПользователю в управляемом интерфейсе:
ТабличнаяЧасть[0]. Чтобы система смогла активировать поле на форме, в пути обязательно должно присутствовать имя колонки или реквизита строки: ТабличнаяЧасть[Индекс].ИмяКолонки. Если указать только имя коллекции и индекс строки, фокус всегда будет сбрасываться на табличное поле целиком.КлючДанных предназначено строго для идентификации объектов информационной базы (ссылок или ключей записей регистров). Для обработок заполнять КлючДанных не требуется: связь с формой выполняется через свойства ПутьКДанным и Поле.НомерСтроки табличной части нумерация начинается с единицы, тогда как в свойстве Поле объекта СообщениеПользователю используется индекс коллекции, начинающийся с нуля (0-based). Передача некорректного индекса приводит к тому, что платформа не находит строку и смещает фокус на всю таблицу."ТабЧасть[" + Индекс + "]") для строк с индексом 1000 и выше стандартная локализация 1С автоматически добавляет неразрывный пробел (разделитель групп разрядов: 1 000). Такой синтаксис ломает путь к данным, и платформенная привязка перестает работать.Рассмотрим базовый сценарий проверки данных непосредственно в модуле формы обработки (на клиенте или на сервере без создания объекта). В этом случае у формы уже есть контекст реквизита Объект.
Посмотрим на пример кода, в котором выполняется обход строк и выдача сообщения с точной привязкой к ячейке:
&НаКлиенте
Процедура ПроверитьТабличнуюЧастьНаКлиенте()
Для Каждого СтрокаТЧ Из Объект.ТабличнаяЧасть Цикл
Если Не ЗначениеЗаполнено(СтрокаТЧ.Реквизит1) Тогда
// Вычисляем индекс строки (начиная с 0)
ИндексСтроки = Объект.ТабличнаяЧасть.Индекс(СтрокаТЧ);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не заполнено обязательное поле!";
// Задаем реквизит формы, к которому привязана табличная часть
Сообщение.ПутьКДанным = "Объект";
// Обязательно убираем группировку разрядов через параметр ЧГ=0
Сообщение.Поле = "ТабличнаяЧасть[" + Формат(ИндексСтроки, "ЧГ=0") + "].Реквизит1";
Сообщение.Сообщить();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Разберем важную альтернативу: свойство ПутьКДанным можно не заполнять отдельно, если указать полный путь к реквизиту прямо в свойстве Поле:
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Поле заполнено некорректно";
Сообщение.Поле = "Объект.ТабличнаяЧасть[" + Формат(ИндексСтроки, "ЧГ=0") + "].Реквизит1";
Сообщение.Сообщить();
Обратите внимание: если таблица создана на форме не как табличная часть реквизита Объект, а как отдельный реквизит формы с типом ТаблицаЗначений (например, ТаблицаФормы), указывать ПутьКДанным = "Объект" нельзя. В этом случае свойство ПутьКДанным оставляем пустым, а в Поле пишем имя реквизита формы: "ТаблицаФормы[" + Формат(ИндексСтроки, "ЧГ=0") + "].ИмяКолонки".
Если алгоритм валидации данных вынесен в модуль объекта (ОбработкаОбъект), стандартный вызов Сообщение.УстановитьДанные(ЭтотОбъект) не сможет самостоятельно связать сообщение с конкретным элементом формы, так как у объекта нет ссылки. Для решения этой задачи перед вызовом серверных методов объекта необходимо зарегистрировать соответствие между формой и объектом обработки.
Разберем реализацию по шагам.
&НаСервере
Процедура ВыполнитьПроверкуНаСервере()
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// Передаем контекст формы в объект
ПараметрыСоответствия = Новый Структура;
ПараметрыСоответствия.Вставить("ИдентификаторФормы", УникальныйИдентификатор);
ПараметрыСоответствия.Вставить("ИмяРеквизита", "Объект");
УстановитьСоответствиеОбъектаИФормы(ОбработкаОбъект, ПараметрыСоответствия);
// Запускаем проверку
ОбработкаОбъект.ПроверитьДанные();
КонецПроцедуры
УстановитьДанные совместно с точным путем к полю:
Процедура ПроверитьДанные() Экспорт
Для Каждого СтрокаТЧ Из ТабличнаяЧасть Цикл
Если СтрокаТЧ.Количество <= 0 Тогда
Индекс = ТабличнаяЧасть.Индекс(СтрокаТЧ);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Количество должно быть больше нуля!";
Сообщение.Поле = "ТабличнаяЧасть[" + Формат(Индекс, "ЧГ=0") + "].Количество";
// Связываем сообщение с текущим экземпляром объекта
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Если конфигурация разработана на основе БСП, рекомендуется использовать готовую процедуру общего модуля. Она самостоятельно обрабатывает переданные параметры и исключает ошибки форматирования:
ИндексСтроки = Объект.ТабличнаяЧасть.Индекс(СтрокаТЧ);
ПутьКПолю = "ТабличнаяЧасть[" + Формат(ИндексСтроки, "ЧГ=0") + "].Реквизит1";
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
"Укажите значение реквизита",
,
ПутьКПолю,
"Объект"
);
Иногда требуется не только прикрепить плашку ошибки к ячейке, но и принудительно перевести фокус интерфейса на проблемную строку. Выполнить это на клиенте можно с помощью свойств элементов формы:
&НаКлиенте
Процедура ПерейтиКСтроке(ИндексСтроки, ИмяКолонки)
ИдентификаторСтроки = Объект.ТабличнаяЧасть[ИндексСтроки].ПолучитьИдентификатор();
// Активируем строку таблицы
Элементы.ТабличнаяЧасть.ТекущаяСтрока = ИдентификаторСтроки;
// Переводим фокус на конкретную колонку
Элементы.ТабличнаяЧасть.ТекущийЭлемент = Элементы["ТабличнаяЧасть" + ИмяКолонки];
КонецПроцедуры
Таким образом, для корректной работы СообщениеПользователю в обработках достаточно помнить три правила: не пытаться заполнять КлючДанных, обязательно указывать имя конкретной колонки в индексе и подавлять группировку разрядов числа с помощью формата ЧГ=0.