Как вывести сообщение пользователю с сервера, если форма документа закрывается после записи

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

В практике разработки на платформе 1С:Предприятие 8 часто возникает ситуация, когда необходимо проинформировать пользователя о результатах каких-либо проверок или автоматических корректировок, выполненных в подписке на событие ПередЗаписью или ПриЗаписи. Однако, если запись объекта инициирована из формы и прошла успешно (без установки Отказ = Истина), платформа стандартно закрывает форму документа. В этот момент все сообщения, вызванные методом Сообщить() или через объект СообщениеПользователю, "схлопываются" вместе с закрывающейся формой, и пользователь просто не успевает их увидеть.

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

Причина исчезновения сообщений

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

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

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

Разберем код, который можно использовать в подписке на событие:


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

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

Решение 2: Передача флага через ДополнительныеСвойства и обработка на клиенте

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

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

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


Источник.ДополнительныеСвойства.Вставить("НужноПоказатьСообщение", Истина);
Источник.ДополнительныеСвойства.Вставить("ТекстСообщенияДляПользователя", "Важные данные обновлены успешно.");

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

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


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

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

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

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

В событии формы ПослеЗаписи мы можем подключить обработчик ожидания:


&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    ПодключитьОбработчикОжидания("ВывестиОтложенноеСообщение", 0.1, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ВывестиОтложенноеСообщение()
    Сообщить("Запись завершена, форма закрыта, но сообщение выведено в глобальный контекст!");
КонецПроцедуры

Благодаря интервалу в 0.1 секунды, процедура ВывестиОтложенноеСообщение сработает уже тогда, когда стек вызовов, связанный с закрытием формы, будет пуст, и сообщение будет направлено в основное окно приложения.

Решение 4: Современные механизмы оповещений (Система взаимодействия)

Проанализируем наиболее современный способ уведомления — использование Системы взаимодействия. Если в вашей организации настроен сервер взаимодействия, вы можете отправлять сообщения пользователю программно из серверного кода напрямую в его чат или всплывающим уведомлением системы. Этот способ вообще не зависит от того, открыта ли какая-то форма или нет.

Посмотрим на пример логики:

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

Рекомендации и выводы

Выясним, какой метод лучше выбрать в зависимости от условий задачи:

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

← На главную