Почему не отображаются сообщения пользователю при нажатии кнопки «Провести и закрыть» и как это исправить?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает ситуация: программист добавляет проверку в подписку на событие ОбработкаПроверкиЗаполнения, выводит информационное сообщение, используя методы БСП через ОбщегоНазначения.СообщитьПользователю, но при использовании кнопки «Провести и закрыть» пользователь ничего не видит. При этом обычное проведение (без закрытия) или проведение из списка документов отрабатывает корректно, отображая текст сообщения. В этой статье мы подробно разберем механику работы платформы, выясним причину «исчезновения» сообщений и рассмотрим способы решения этой задачи.

Анализируем причину проблемы

Для начала давайте разберем, что происходит в системе в момент нажатия кнопки «Провести и закрыть». Когда пользователь инициирует эту команду, платформа выполняет следующие действия:

  1. Отправляет данные на сервер для записи и проведения объекта.
  2. На сервере срабатывают стандартные обработчики и подписки на события, включая ОбработкаПроверкиЗаполнения, где описывается модель данных объекта.
  3. Метод СообщениеПользователю (или обертка БСП ОбщегоНазначения.СообщитьПользователю) формирует сообщение и помещает его в специальный буфер в памяти сервера.
  4. После успешного завершения транзакции сервер возвращает управление клиенту.
  5. Критический момент: Поскольку была вызвана команда «Провести и закрыть», платформа немедленно инициирует закрытие формы документа.

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

Механизм «осиротевших» сообщений

Рассмотрим подробнее объект СообщениеПользователю. У него есть важное свойство — ИдентификаторНазначения (TargetID). Это уникальный идентификатор формы, к которой должно быть «привязано» сообщение. Если этот идентификатор не заполнен, платформа пытается привязать сообщение к активному окну.

В момент записи документа из формы активным окном считается сама форма документа. При нажатии «Провести и закрыть» последовательность действий такова, что форма закрывается раньше, чем пользователь успевает прочитать сообщение. Именно поэтому при установке флага Отказ = Истина сообщение всегда видно — в этом случае проведение прерывается, форма не закрывается, и фокус остается на ней.

Решение 1: Использование Идентификатора назначения

Если мы хотим, чтобы сообщение «выжило» после закрытия формы и отобразилось, например, в форме списка, нам нужно явно указать, какой форме оно принадлежит. Рассмотрим пример кода, который можно использовать для настройки объекта СообщениеПользователю:


НовоеСообщение = Новый СообщениеПользователю;
НовоеСообщение.Текст = "Документ успешно проверен, но обратите внимание на дополнительные данные.";
// Если мы знаем ID формы списка, мы можем его установить
// НовоеСообщение.ИдентификаторНазначения = ИдентификаторФормыСписка;
НовоеСообщение.Сообщить();

Однако здесь мы сталкиваемся с техническим ограничением: внутри подписки на событие (на уровне сервера) объект ДокументОбъект ничего не знает о том, из какой формы он был открыт. У него нет доступа к идентификаторам открытых окон клиента.

Решение 2: Передача управления на сторону клиента (рекомендуемый способ)

Чтобы гарантированно показать уведомление пользователю, которое не исчезнет при закрытии окна, лучше всего использовать механизм оповещений — для этого есть готовая настройка и вывод произвольных оповещений в 1С. В отличие от сообщений, привязанных к форме, метод ПоказатьОповещениеПользователя создает всплывающее окно в углу экрана, которое живет независимо от того, закрыта форма документа или нет.

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

Шаг 1. В подписке на событие (Сервер):

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


Процедура ПриОбработкеПроверкиЗаполнения(Источник, Отказ, ПроверяемыеРеквизиты) Экспорт
    // Определенное условие проверки
    Если Источник.СуммаДокумента > 1000000 Тогда
        Источник.ДополнительныеСвойства.Вставить("ТекстПредупрежденияДляКлиента", "Внимание: Сумма документа превышает лимит!");
    КонецЕсли;
КонецПроцедуры

Шаг 2. В форме документа (Клиент):

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


&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    
    // Проверяем наличие сообщения, переданного через ДополнительныеСвойства
    // Для этого придется вызвать серверный метод, если данные не были переданы в параметрах
    ТекстСообщения = "";
    Если ЭтаФорма.Объект.ДополнительныеСвойства.Свойство("ТекстПредупрежденияДляКлиента", ТекстСообщения) Тогда
        ПоказатьОповещениеПользователя("Результат проверки", , ТекстСообщения);
    КонецЕсли;
    
КонецПроцедуры

Решение 3: Использование параметров сеанса или временного хранилища

Если вам критически важно вывести сообщение именно в панель сообщений формы списка, можно применить более сложную схему:

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

Рассмотрим пример записи в хранилище:


АдресХранилища = ПоместитьВоВременноеХранилище(ТекстСообщения, Новый УникальныйИдентификатор);
// Передаем адрес на клиент через параметры или свойства

Однако помните, что такой подход избыточен для простых уведомлений и нагружает систему лишними серверными вызовами.

Почему Отказ = Истина решает проблему?

Как отмечалось в обсуждении, если установить Отказ = Истина, сообщение отображается всегда. Давайте проанализируем ситуацию. Когда платформа видит, что Отказ установлен в значение Истина, она прерывает выполнение команды закрытия формы. Форма остается «грязной» (измененной) и открытой перед глазами пользователя. В этот момент все сообщения, накопленные в буфере серверного вызова, успешно доставляются в активное окно.

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

Подведем итоги

Проанализировав ситуацию, мы выяснили, что отсутствие сообщений при команде «Провести и закрыть» — это не ошибка кода, а следствие логики работы интерфейса управляемого приложения. Для решения проблемы мы можем выбрать один из трех путей:

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

← На главную