Как задать вопрос пользователю и скорректировать табличную часть при создании документа на основании в управляемых формах?

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

При реализации бизнес-логики в 1С:Предприятии 8.3 на управляемых формах часто возникает задача: пользователь создает документ вводом на основании, срабатывает типовая ОбработкаЗаполнения, табличные части документа заполняются, и форма отображается на экране. Сразу после этого необходимо спросить у пользователя подтверждение на дополнительную корректировку строк (например, пересчет скидок, перезаполнение цен или удаление определенных позиций) и при согласии изменить данные.

Разберем по шагам, с какими сложностями сталкивается разработчик в этой ситуации, в каком событии формы инициировать диалог, какие асинхронные методы использовать и как гарантировать корректное отображение формы до вызова диалогового окна.

Анализ проблемы: жизненный цикл управляемой формы и отрисовка интерфейса

Рассмотрим, как платформа открывает форму создаваемого на основании документа. Сначала на сервере отрабатывают события ОбработкаЗаполнения в модуле объекта и ПриСозданииНаСервере в модуле формы. Затем управление передается на клиент в процедуру ПриОткрытии. Однако в этот момент графический интерфейс формы еще окончательно не сформирован.

Если мы попытаемся вызвать диалог вопроса непосредственно внутри тела процедуры ПриОткрытии, в тонком клиенте или веб-клиенте модальное/асинхронное окно появится поверх еще не прорисованного пустого серого окна документа. Табличная часть не будет визуализирована перед глазами пользователя, что противоречит исходной задаче. Полная прорисовка элементов формы завершается только тогда, когда поток выполнения полностью выходит из процедуры ПриОткрытии и возвращается в системный цикл событий платформы.

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

Способ 1. Использование обработчика ожидания после события ПриОткрытии

Рассмотрим классический и наиболее надежный способ: запуск однократного обработчика ожидания с минимальной задержкой в событии ПриОткрытии. Это позволяет форме завершить полный цикл визуализации на клиенте, после чего платформа сразу выполнит наш клиентский метод с вопросом.

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

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

Посмотрим на пример реализации с применением асинхронной функции ВопросАсинх() и ключевого слова Ждать:


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

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

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

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

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

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

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


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

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

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

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

Способ 2. Вынос вопроса в форму документа-основания (архитектурная альтернатива)

Проанализируем альтернативный подход, который позволяет избежать мерцания экрана и использования обработчиков ожидания. Если логика корректировки известна заранее, диалог с пользователем можно перенести в исходный документ, из которого инициируется ввод на основании.

Разберем, как устроен этот подход:

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

Посмотрим на пример клиентского кода в исходном документе:


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

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

Сравнение методов: ВопросАсинх или ПоказатьВопрос?

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

Разница заключается в синтаксисе:

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

Таким образом, для решения задачи оптимально использовать подключение однократного обработчика ожидания в ПриОткрытии в сочетании с ВопросАсинх() или перенести вопрос непосредственно в команду создания документа-источника.

← На главную