Вывод сообщений пользователю из закрывающейся управляемой формы 1С

Введение

В управляемом интерфейсе 1С, сообщения, выводимые пользователю с помощью функции Сообщить(...) или объекта СообщениеПользователю, отображаются с привязкой к форме. И даже если явно такая привязка не задана, то платформа их автоматически привязывает к текущей активной форме.

В общем случае такое поведение системы весьма удобно и разумно.
Но есть ситуация, когда оно имеет негативный побочный эффект.

Чаще всего такая ситуация возникает, когда пользователь в форме документа или справочника нажимает на кнопку "Провести и закрыть" или "Записать и закрыть".
Если во время записи объекта, или во время проведения документа, пользователю выводятся какие-то предупреждающие сообщения (которые не приводят к отмене выполняемого действия), то сообщения выводятся в форму, которая по окончании выполнения кода закрывается, и пользователь эти сообщения не замечает (и возможности их посмотреть у него уже нет).

Вот для того, чтобы эти сообщения все-таки "донести" до пользователя, я и придумал описанный ниже прием.

Впервые этот прием был описан мною в обсуждении темы на Инфостарте.
Здесь же я проверил свои предположения о возможности оптимизации описанной там версии приема, и описал уже результирующую оптимизированную версию.

Ограничения

Т.к. платформа 1С не предоставляет возможности работать с сообщениями, выведенными из клиентского контекста, то описанный ниже прием работает только для тех сообщений, которые выводятся в серверном контексте исполнения кода.
А так как сохранение объектов и проведение документов выполняется в серверном контексте, то нам такое решение вполне подходит.

Общая идея

Общая идея метода заключается в том, чтобы перед возвратом из серверного контекста в клиентский, сохранять сообщения пользователю в специально созданном для этого реквизите формы. А при закрытии формы, если в этом реквизите есть какие-то сообщения, то отображать их, изменяя идентификатор назначения сообщения на пустой GUID. В этом случае, сообщения будут привязываться к текущей активной форме. Но так как это все происходит при закрытии текущей формы, то сообщения будут привязаны к форме, которая станет активной после закрытия текущей формы.

Ну и естественно, что нужно следить за очисткой этого списка сообщений, если форма не закрывается (и сообщения пользователю отобразила платформа).

Подробности реализации на примере

Обоснование

Для того, чтобы продемонстрировать техническую реализацию данного метода, возьмем для примера типовую конфигурацию "Бухгалтерия для Украины 2.0" (2.0.23.1). В ней при проведении документа "Приложение 2 к Налоговой накладной", если документ не включен в ЕРНН, пользователю в окно сообщений выдается предупреждение

"Не указана дата регистрации документа в ЕРНН покупателем! Проводки сформированы частично".

Но если пользователь нажимает на кнопку "Провести и закрыть", то он это предупреждение не увидит (см. видео).

Скачать: Видео в формате MPEG 4 (.mp4) 1280x720 (1.53 МБ) Видео в формате WebM (.webm) 1280x720 (1.59 МБ) Видео в формате Ogg (.ogv) 1280x720 (7.97 МБ)

Добавление реквизита формы

Для хранения сообщений, которые нужно отобразить пользователю при закрытии формы, в реквизиты формы документа Приложение2КНалоговойНакладной добавим реквизит типа Список значений.
Назовем его, например, ХДЖ_СообщенияПользователюПослеЗаписи.
Ну а чтобы "следующим поколениям разработчиков" было понятно "что это за реквизит" и "зачем он нужен", можно оставить им послание, описывающее назначение этого реквизита, в его свойстве Заголовок (так как на форме мы его все-равно отображать не будем):

После записи объекта, в этом реквизите сохраняются все выводимые пользователю сообщения. А при закрытии формы, чтобы они не пропали, они выводятся в родительскую форму.

Добавление реквизита формы

Сохранение сообщений после записи на сервере

Следующим шагом нужно в обработчике события формы ПослеЗаписиНаСервере(...) выбирать готовящиеся к отображению сообщения пользователю, и сохранять их в добавленном выше реквизите формы.

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
	...
	//(Назаренко_СВ 2021-01-24
	// Если в процессе записи пользователю выдавались какие-либо сообщения,
	// то перед отображением их ему, сохраним их копии,
	// чтобы в случае записи во время закрытия формы, отобразить их ему
	// (т.к. после закрытия формы он их уже не увидит).
	ХДЖ_СообщенияПользователюПослеЗаписи.Очистить();
	Сообщения = ПолучитьСообщенияПользователю(Ложь);
	Для Каждого Сообщение Из Сообщения Цикл
		ХДЖ_СообщенияПользователюПослеЗаписи.Добавить(Сообщение);
	КонецЦикла;
	//)Назаренко_СВ
КонецПроцедуры
		

Вывод сообщений в родительское окно при закрытии формы

В обработчике события формы ПриЗакрытии(...), хранимые в добавленном выше реквизите формы сообщения пользователю, выведем в окно, которое станет активным после закрытия текущей формы.
Делаем это только в том случае, если окно закрывается без завершения работы системы, так как при завершении работы системы закроются все окна, и куда бы мы эти сообщения ни вывели, пользователь все-равно их не увидит.

&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
	...
	//(Назаренко_СВ 2021-01-24
	Если ЗавершениеРаботы <> Истина Тогда // В режиме совместимости 8.3.7 и ниже параметр ЗавершениеРаботы принимает значение Неопределено.
		// Перенаправим собранные при записи объекта,
		// и еще не отображенные пользователю, сообщения в форму,
		// которая станет активной после закрытия этой формы
		// (т.к. в противном случае форма будет закрыта и пользователь не увидит этих сообщений).
		ПустойУИД = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000");
		Для Каждого Элемент Из ХДЖ_СообщенияПользователюПослеЗаписи Цикл
			Сообщение = Элемент.Значение;
			Сообщение.ИдентификаторНазначения = ПустойУИД;
			Сообщение.Сообщить();
		КонецЦикла;
	КонецЕсли;
	//)Назаренко_СВ
КонецПроцедуры
		

Удаление сообщений, если форма не закрылась (и они отобразились пользователю платформой)

В обработчике события формы ПослеЗаписи(...), подключим обработчик ожидания, который вызовется через минимально возможное время - 0.1 сек. Но вызовется он только в том случае, если форма не закроется. Если же запись объекта была при закрытии формы, то этот обработчик вызван не будет.

&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
	....
	//(Назаренко_СВ 2021-01-24
	// Подключим обработчик очистки собранных сообщений пользователю,
	// который будет выполнен только в случае, если запись выполнялась без закрытия формы.
	ПодключитьОбработчикОжидания("ОбработчикОжиданияОчисткиСобранныхПриЗаписиСообщенийПользователю", 0.1, Истина);
	//)Назаренко_СВ
КонецПроцедуры
		

В самом же обработчике события просто очищаем список сохраненных сообщений пользователю, так как, если он вызвался, значит форма не закрылась и сообщения пользователю отобразила платформа.

// Назаренко_СВ 2021-01-24
//
// Обработчик ожидания, который подключается после записи объекта,
// и вызывается однократно, если запись объекта выполнялась без закрытия формы.
// Очищает список собранных во время записи объекта сообщений пользователю.
//
//Параметры:
// НЕТ
//
&НаКлиенте
Процедура ОбработчикОжиданияОчисткиСобранныхПриЗаписиСообщенийПользователю()
	ХДЖ_СообщенияПользователюПослеЗаписи.Очистить();
КонецПроцедуры
		

Демонстрация результата

В результате мы получили более дружелюбное к пользователю поведение системы (см. видео).

Скачать: Видео в формате MPEG 4 (.mp4) 1280x720 (20.4 МБ) Видео в формате WebM (.webm) 1280x720 (4.69 МБ) Видео в формате Ogg (.ogv) 1280x720 (58 МБ)

О Лицензии

Ну и для паразитов, любящих таскать честных людей по судам - пару слов о лицензии.
Вы можете пользоваться этим приемом (и приведенным здесь кодом) в любых благих целях, и при этом ничего мне не должны.
С другой стороны, и ответственности за прямой или косвенный ущерб, а также за то, что полученная в результате использования данного приема функциональность не соответствует Вашим ожиданиям, я не несу.
Вы используете приведенный выше код (как и другие мои продукты) на свой страх и риск.