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