Как последовательно открывать формы новых элементов справочника с ожиданием действий пользователя в 1С

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

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

Разберем причины такого поведения платформы 1С:Предприятие 8.3 и подробно рассмотрим корректные способы решения данной задачи.

Почему не работает вызов формы в обычном цикле

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

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

Способ 1. Асинхронная цепочка через ОписаниеОповещения (Рекомендуемый)

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

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

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

Посмотрим на пример программного кода:


&НаКлиенте
Процедура НачатьПоследовательнуюОбработку(Команда)
    // ОчередьДанных - массив структур, сформированный из файла Excel
    ИндексТекущегоЭлемента = 0;
    ОбработатьСледующийЭлемент();
КонецПроцедуры

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

    ТекущиеДанные = ОчередьДанных[ИндексТекущегоЭлемента];

    // Заполняем структуру начальных значений для нового объекта
    ПараметрыЗаполнения = Новый Структура;
    ПараметрыЗаполнения.Вставить("Наименование", ТекущиеДанные.Наименование);

    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("ЗначенияЗаполнения", ПараметрыЗаполнения);

    // Формируем оповещение, которое сработает строго после закрытия окна оператором
    ОповещениеОЗакрытии = Новый ОписаниеОповещения("ПослеЗакрытияФормыЭлемента", ЭтотОбъект);

    ОткрытьФорму(
        "Справочник.Контрагенты.ФормаОбъекта",
        ПараметрыОткрытия,
        ЭтотОбъект,
        Истина,
        ,
        ,
        ОповещениеОЗакрытии,
        РежимОткрытияОкнаФормы.БлокироватьОкноВладельца
    );
КонецПроцедуры

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

Такой подход гарантирует корректную работу в тонком клиенте и веб-клиенте, предотвращает открытие лишних окон и не нарушает принципы асинхронной архитектуры платформы 1С.

Способ 2. Использование модального режима (Устаревший)

Исторически в платформе 1С применялся метод Форма.ОткрытьМодально(), который полностью останавливал выполнение встроенного языка до момента закрытия открытого окна. В обычном цикле это выглядело бы так:


Для Каждого Стр Из ТаблицаИмен Цикл
    Форма = ПолучитьФорму("Справочник.Контрагенты.ФормаОбъекта");
    Форма.Объект.Наименование = Стр.Наименование;
    Форма.ОткрытьМодально();
КонецЦикла;

Однако при вызове модального окна в современной конфигурации разработчик сталкивается с ошибкой «Использование модальных окон в данном режиме запрещено». Для ее устранения требуется изменить свойство конфигурации Режим использования модальности на значение Использовать.

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

Способ 3. Пакетная обработка через табличную часть (Оптимальный UX)

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

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

Посмотрим на пример серверной процедуры создания объектов:


&НаСервере
Процедура СоздатьКонтрагентовНаСервере()
    Для Каждого Стр Из ТаблицаКонтрагентов Цикл
        Если Не Стр.Пометка Тогда
            Продолжить;
        КонецЕсли;

        НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
        НовыйКонтрагент.Наименование = Стр.Наименование;
        НовыйКонтрагент.ОсновнойМенеджер = Стр.ОсновнойМенеджер;
        
        Попытка
            НовыйКонтрагент.Записать();
            Стр.Создан = Истина;
        Исключение
            // Запись ошибки в лог или вывод сообщения пользователю
            ВызватьИсключение;
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

Такой подход исключает рутинное закрытие сотен окон оператором и существенно ускоряет работу программы.

← На главную