Введение
Когда встает задача при записи объекта выводить неблокирующее сообщение, то обычно возникает проблема - при нажатии стандартных команд "Записать и закрыть" или "Провести и закрыть" сообщение формируется, но пользователь его не увидит. Т.к. все сообщения будут выведены на текущую форму, а затем эта же форма закроется, унеся с собой и все наши сообщения. Проблема всплывала на форумах, лично у меня возникала потребность в решении этой проблемы, а также есть статья, посвященная данной теме, но в ней предлагается использовать предупреждения вместо сообщений, что совсем не то, чего хочется. Поэтому в данной статье хочется поставить точку в этой теме, разобрать, почему вообще это происходит, и поделиться решением, которое, на мой взгляд, является наиболее корректным.
Решение
Прежде чем решать проблему, разберёмся в механике платформы, которая приводит к потере сообщений. Ниже приведена схема событий при нажатии команды "Записать и закрыть" для справочника. При работе с формой документа схема будет похожа и принципиальных различий, влияющих на понимание принципа и реализацию, не будет.

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

Предложенный подход решает проблему демонстрации неблокирующих сообщений при использовании команд закрытия формы. Ключевая идея заключается в перехвате сообщений в последнем серверном событии и их отложенном выводе уже после закрытия формы, когда управление вернётся активному окну. Это решение:
- Сохраняет логику работы - не заменяет сообщения на предупреждения и другие способы коммуникации с пользователем.
- Является универсальным - работает для документов, справочников и других объектов.
Таким образом, мы получаем рабочий и предсказуемый механизм, который позволяет пользователю видеть все информационные сообщения, даже если он завершает работу с объектом через команды "Записать и закрыть" или "Провести и закрыть".
Вступайте в нашу телеграмм-группу Инфостарт
