В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда стандартный механизм СообщениеПользователю ведет себя непредсказуемо. Одной из самых коварных проблем является случай, когда платформа визуально отмечает поле ввода красной линией (как при ошибке заполнения), но само «облачко» с текстом сообщения не появляется. Это сбивает пользователя с толку и делает интерфейс менее информативным. Особенно часто это проявляется во внешних обработках и при использовании асинхронных вызовов.
В данной статье мы подробно проанализируем, почему так происходит, и разберем по шагам, как обеспечить гарантированный вывод сообщений пользователю в сложных сценариях взаимодействия клиента и сервера.
Типичный сценарий, при котором возникает ошибка, выглядит следующим образом: на форме внешней обработки существует реквизит, связанный с полем ввода. По нажатию кнопки вызывается цепочка асинхронных методов, например, ПоказатьВопрос, а затем ПоказатьВводСтроки. После получения данных от пользователя управление передается в серверную процедуру модуля формы, где создается объект СообщениеПользователю.
Проанализируем программный код, который обычно приводит к «частичному» срабатыванию:
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Поле заполнено некорректно!";
Сообщение.Поле = "Объект.ИмяРеквизита";
Сообщение.Сообщить();
В результате выполнения этого кода внизу окна 1С появляется общая панель сообщений, само поле на форме подчеркивается красным, но всплывающее окно с пояснением рядом с полем отсутствует. Если же вызвать ту же серверную процедуру напрямую, без асинхронных диалогов, сообщение выводится корректно. Это наталкивает на мысль о потере связи между сообщением и визуальным контекстом формы.
Основная причина такого поведения кроется в особенностях работы управляемого интерфейса в асинхронном режиме. Рассмотрим подробнее, что происходит внутри платформы:
ПоказатьВводСтроки, это окно начинает закрываться.СообщениеПользователю. В этот момент клиентское приложение еще находится в процессе «перерисовки» фокуса с закрытого модального (асинхронного) окна на основную форму.Интересное наблюдение: если поставить точку останова перед методом Сообщить() и подождать пару секунд, сообщение отобразится корректно. Это подтверждает теорию о том, что платформе просто не хватает времени на завершение внутренних процессов переключения интерфейса.
Для того чтобы платформа «не теряла» форму, особенно если речь идет о внешней обработке, необходимо явно указывать, какой форме предназначается сообщение. У объекта СообщениеПользователю есть свойство ИдентификаторНазначения.
Рассмотрим, как правильно модифицировать код на сервере:
// В процедуру на сервере нужно передать УникальныйИдентификатор формы
Процедура ОбработатьДанныеНаСервере(ИдентификаторФормы)
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Ошибка в данных!";
Сообщение.Поле = "Объект.ИмяРеквизита"; // Путь к данным
// Указываем платформе конкретное окно
Сообщение.ИдентификаторНазначения = ИдентификаторФормы;
Сообщение.Сообщить();
КонецПроцедуры
В сложных формах, где используются динамические списки или реквизиты, не входящие в основной Объект, платформе бывает трудно сопоставить путь, указанный в строке Сообщение.Поле, с реальным элементом формы. Для этого разработчики 1С предусмотрели метод УстановитьДанные() и механизм сопоставления.
Проанализируем ситуацию, когда реквизит принадлежит объекту обработки. Посмотрим на пример кода:
// Преобразуем данные формы в прикладной объект (если нужно работать с методами объекта)
ОбъектОбработки = РеквизитФормыВЗначение("Объект");
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Неверное значение!";
Сообщение.Поле = "ИмяРеквизита"; // Здесь уже без префикса "Объект"
Сообщение.УстановитьДанные(ОбъектОбработки);
Сообщение.Сообщить();
Важный момент: если вы используете УстановитьДанные(), убедитесь, что путь в свойстве Поле соответствует имени реквизита в метаданных самого объекта, а не пути к данным на форме.
Если сообщение выводится из модуля формы, крайне эффективно работает метод УстановитьСоответствиеОбъектаИРеквизитаФормы(). Это «подсказывает» платформе связь между объектом данных на сервере и его визуальным представлением.
Разберем пример реализации:
// В модуле формы
УстановитьСоответствиеОбъектаИРеквизитаФормы(Объект, "Объект");
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Внимание!";
Сообщение.Поле = "ИмяРеквизита";
Сообщение.КлючДанных = Объект; // Или ссылка, если это документ/справочник
Сообщение.Сообщить();
Если вышеуказанные методы не помогают из-за слишком сложной цепочки асинхронных вызовов, стоит рассмотреть архитектурное решение, применяемое в Библиотеке стандартных подсистем (БСП). Вместо того чтобы вызывать Сообщить() глубоко в серверном коде, мы собираем массив сообщений и возвращаем его на клиент.
Посмотрим на алгоритм:
Сообщить().Это гарантирует, что в момент вызова сообщения форма полностью активна, фокус установлен, и платформа готова к отрисовке визуальных компонентов.
Отсутствие текста сообщения при наличии красного подчеркивания — это не ошибка логики программиста, а особенность синхронизации интерфейсного потока 1С. Чтобы избежать этой проблемы, придерживайтесь следующих правил:
Поле: он должен точно совпадать с путем в свойствах элемента формы.УстановитьДанные(), если сообщение формируется на основе объектных данных.Применяя эти методы, мы обеспечим стабильную работу интерфейса и корректное информирование пользователя о допущенных ошибках даже в самых сложных асинхронных сценариях.