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