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