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