Как задать вопрос пользователю в событии ПередЗаписью при запрете модальности в 1С

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

При разработке конфигураций в режиме запрета модальных вызовов разработчики часто сталкиваются с классической задачей: перед сохранением объекта на клиенте необходимо задать пользователю вопрос и в зависимости от ответа продолжить запись или установить отказ. В обычном приложении или при разрешенной модальности это решалось синхронным вызовом функции Вопрос(). В управляемом приложении без модальности этот подход не работает.

Проанализируем природу проблемы и разберем надежные варианты реализации немодального подтверждения записи.

В чем заключается сложность асинхронного вызова в ПередЗаписью

Событие формы ПередЗаписью вызывается платформой синхронно. Это означает, что процедура-обработчик обязана сразу вернуть управление платформе, выставив или не выставив параметр Отказ = Истина.

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

Кроме того, находясь в событии ПередЗаписью, стандартными средствами нельзя однозначно определить, какое действие инициировал пользователь: команду Записать или команду Записать и закрыть. При отмене записи признак последующего закрытия формы теряется.

Решение 1: Паттерн «Двойной вход» через ПараметрыЗаписи

Рассмотрим основной и наиболее универсальный способ решения задачи без переопределения стандартных кнопок командной панели. Алгоритм строится на двухэтапном прохождении обработчика ПередЗаписью:

  1. Первый вход: проверяем, было ли уже получено подтверждение. Если нет — устанавливаем Отказ = Истина, прерываем текущую запись и открываем немодальный вопрос.
  2. Обработка ответа: если пользователь ответил утвердительно, помещаем флаг подтверждения в структуру параметров записи и программно вызываем ЭтаФорма.Записать(ПараметрыЗаписи).
  3. Второй вход: платформа снова вызывает ПередЗаписью, но на этот раз в структуре ПараметрыЗаписи уже присутствует наш флаг. Мы пропускаем блок вопроса, Отказ остается равным Ложь, и объект успешно сохраняется.

Разберем по шагам реализацию данного механизма на клиенте:


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

&НаКлиенте
Процедура ПослеВопросаОЗаписи(РезультатВопроса, ДополнительныеПараметры) Экспорт
    
    Если РезультатВопроса = КодВозвратаДиалога.Да Тогда
        
        ПараметрыЗаписи = ДополнительныеПараметры.ПараметрыЗаписи;
        ПараметрыЗаписи.Вставить("ПодтвержденоПользователем", Истина);
        
        // Повторно инициируем запись формы с передачей признака успешной проверки
        ЭтаФорма.Записать(ПараметрыЗаписи);
        
    КонецЕсли;
    
КонецПроцедуры

Обработка сценария «Записать и закрыть»

Вышеописанный подход отлично работает для кнопки «Записать». Однако если пользователь нажал «Записать и закрыть», после вызова ЭтаФорма.Записать(ПараметрыЗаписи) форма останется открытой, так как платформа воспримет это как обычную запись из встроенного языка.

Чтобы восстановить поведение закрытия, разберем дополнение логики с использованием события ПослеЗаписи и дополнительного флага:


&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    
    // Если был передан признак закрытия формы после успешной записи
    Если ПараметрыЗаписи.Свойство("ЗакрытьПослеЗаписи") И ПараметрыЗаписи.ЗакрытьПослеЗаписи Тогда
        ЭтаФорма.Закрыть();
    КонецЕсли;
    
КонецПроцедуры

Решение 2: Использование собственных команд формы

Если логика формы требует четкого разграничения действий пользователя («Записать», «Провести и закрыть», «Записать и закрыть»), надежным решением является отказ от стандартных команд в командной панели формы и замена их на пользовательские команды.

Разберем порядок действий при реализации собственных команд:

  1. Отключаем видимость или доступность стандартных команд в командной панели формы (свойства командной панели или команд формы).
  2. Создаем пользовательские команды: КомандаЗаписать и КомандаЗаписатьИЗакрыть.
  3. В обработчике команды сначала выполняем все проверки и задаем немодальный вопрос.
  4. Только после получения утвердительного ответа вызываем метод ЭтаФорма.Записать(), а для второй команды следом вызываем ЭтаФорма.Закрыть().

Посмотрим на пример кода клиентской команды:


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

&НаКлиенте
Процедура ПослеПодтвержденияЗаписиИЗакрытия(РезультатВопроса, ДополнительныеПараметры) Экспорт
    
    Если РезультатВопроса = КодВозвратаДиалога.Да Тогда
        ВыполнитьЗаписьИЗакрытие();
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьЗаписьИЗакрытие()
    
    ПараметрыЗаписи = Новый Структура;
    Если ЭтаФорма.Записать(ПараметрыЗаписи) Тогда
        ЭтаФорма.Закрыть();
    КонецЕсли;
    
КонецПроцедуры

Решение 3: Перенос логики в статусную модель или подтверждающий флаг

В современных интерфейсах 1С часто рекомендуется избегать лишних всплывающих диалоговых окон, прерывающих работу пользователя. Вместо диалога «Да/Нет» в момент сохранения можно использовать более прозрачный для интерфейса паттерн:

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

Этот подход исключает проблемы с асинхронными вызовами в системных событиях и полностью соответствует стандартам разработки интерфейсов 1С.

← На главную