Как задать вопрос пользователю при изменении реквизита на управляемой форме 1С

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

В разработке на платформе 1С:Предприятие 8.3 (Управляемые формы) часто возникает задача: при выборе пользователем определенного значения в поле ввода необходимо выдать предупреждение или задать вопрос. Если пользователь согласен, данные меняются и выполняются сопутствующие действия; если нет — выбор должен быть аннулирован. Сложность заключается в том, что в управляемом интерфейсе диалоговые окна (такие как ПоказатьВопрос) работают асинхронно. Это означает, что код не останавливается в ожидании ответа, а продолжает выполнение.

В этой статье мы подробно разберем, как правильно реализовать такую логику, используя события элементов формы и механизм описания оповещений.

Разберем проблему: почему обычный вопрос не работает

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

Решение через событие ОбработкаВыбора

Проанализируем наиболее эффективный метод решения задачи. Мы будем использовать событие ОбработкаВыбора элемента формы. Этот метод хорош тем, что позволяет перехватить значение до того, как оно будет фактически записано в реквизит объекта.

Алгоритм действий следующий:

  1. В процедуре ОбработкаВыбора проверяем, является ли выбранное значение "опасным" или требующим подтверждения.
  2. Если подтверждение нужно, мы устанавливаем СтандартнаяОбработка = Ложь. Это предотвращает автоматическое изменение реквизита.
  3. Вызываем процедуру ПоказатьВопрос, передавая в нее ОписаниеОповещения. В дополнительные параметры описания оповещения мы помещаем само выбранное значение.
  4. В экспортной процедуре-обработчике анализируем ответ пользователя и, если он нажал "Да", программно присваиваем значение реквизиту.

Рассмотрим пример кода:


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

КонецПроцедуры

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

Метод с использованием временного хранения предыдущего значения

Иногда логику удобнее реализовать в событии ПриИзменении. Однако к моменту срабатывания этого события реквизит уже изменен, и мы "потеряли" старое значение. Чтобы иметь возможность откатиться назад без обращения к базе данных, проанализируем следующий прием:

Создадим Реквизит формы (не путать с реквизитом объекта), например, СтароеЗначениеВидаОперации. При открытии формы или после успешного изменения будем записывать туда текущее состояние. Если пользователь в диалоге нажмет "Нет", мы просто вернем значение из этого вспомогательного реквизита.

Посмотрим на пример реализации:


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

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

Использование стандартных свойств предупреждения

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

Если включить эти свойства, то при любом изменении поля платформа сама будет выдавать вопрос пользователю. Это решение не требует написания кода для вызова диалога, но оно менее гибкое: вопрос будет задаваться всегда, а не только при выборе конкретного "опасного" значения.

Обработка очистки значения

Важно помнить, что пользователь может не только выбрать новое значение, но и очистить поле (нажать на "крестик"). В этом случае событие ОбработкаВыбора не сработает. Чтобы обеспечить полную безопасность данных, следует также использовать событие ОбработкаОчистки.


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

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

Рекомендации по UX (пользовательскому опыту)

Проанализируем ситуацию с точки зрения удобства пользователя. Частые всплывающие окна раздражают и со временем приводят к тому, что человек нажимает "Да" машинально. Рассмотрим альтернативные варианты:

Таким образом, использование ОписаниеОповещения в связке с ОбработкаВыбора является наиболее гибким техническим решением для управляемых форм 1С, позволяющим программно контролировать действия пользователя и сохранять целостность данных в интерактивном режиме.

← На главную