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