Как открыть форму, внести изменения и получить значение обратно в 1С 8.3

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

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

Почему обычный цикл не работает?

Проанализируем классическую ошибку: попытку использовать цикл Для каждого или Для, внутри которого вызывается ОткрытьФорму. В управляемом приложении метод ОткрытьФорму не останавливает выполнение основного кода. Программа просто «пробрасывает» команду на открытие окна и тут же переходит к следующей итерации цикла. В итоге у пользователя одновременно откроется десяток окон, а код завершит свою работу, так и не дождавшись ввода данных.

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

Шаг 1. Подготовка механизма рекурсивного обхода

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

Рассмотрим пример кода в модуле формы. Предположим, у нас есть табличная часть ТЧ_Данные и нам нужно заполнить реквизит НужныйРеквизит.


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

Шаг 2. Реализация обработчика оповещения

Когда пользователь заполнит реквизит в справочнике, нажмет кнопку «Записать и закрыть», форма закроется, и управление передастся в процедуру, которую мы указали в ОписаниеОповещения. Выясним, как получить измененные данные.


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

Шаг 3. Возврат значения из формы справочника

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

Например, в форме объекта справочника «Облигации»:


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

В этом случае в процедуре ПослеЗакрытияФормыСправочника в переменной РезультатЗакрытия окажется именно то значение, которое мы передали в метод Закрыть(). Это позволяет избежать лишних серверных вызовов для получения обновленных данных.

Важные технические нюансы

Проанализируем еще несколько критических моментов, которые помогут избежать ошибок:

  1. Контекст исполнения: Код открытия формы и оповещения всегда выполняется на клиенте (&НаКлиенте). Проверка реквизитов ссылки и получение данных из базы данных — на сервере (&НаСервере или &НаСервереБезКонтекста).
  2. Блокировка окна владельца: Использование РежимОткрытияОкнаФормы.БлокироватьОкноВладельца крайне рекомендуется. Это предотвратит ситуацию, когда пользователь, не закрыв справочник, решит нажать кнопку запуска обработки еще раз, что приведет к непредсказуемому наложению рекурсий.
  3. Передача владельца: При вызове ОткрытьФорму третьим параметром мы передаем ЭтаФорма. Это делает текущую форму «владельцем» новой формы, что важно для корректной работы оповещений и блокировок.
  4. Обработка отказа: Если пользователь просто закрыл форму справочника крестиком, не заполнив данные, РезультатЗакрытия будет равен Неопределено. Проанализируйте этот случай в коде, чтобы не возникло зацикливания на одной и той же «плохой» строке.

Итоги работы алгоритма

Рассмотрим, как теперь выглядит процесс для пользователя: он нажимает кнопку, система проверяет строки. Как только встречается пустая строка, перед пользователем возникает окно справочника. Пока оно открыто, основная форма недоступна. Пользователь вносит изменения, нажимает «Записать и закрыть». Окно исчезает, и система тут же переходит к следующей проверке или открывает следующее окно, если это требуется. Это выглядит как бесшовный процесс, полностью соответствующий стандартам разработки 1С 8.3.

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

← На главную