Как передать данные из формы-помощника в основную форму и создать новую строку в 1С?

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

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

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

Анализ частой ошибки: прямое обращение к форме-владельцу

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


&НаКлиенте
Процедура ЗаполнитьНовуюСтроку(Команда)
    СтруктураНовойСтроки = ПолучитьСтруктуруПараметровСэндвичПанели();
    // ОШИБКА: Прямое обращение к объекту владельца
    НоваяСтрока = ЭтаФорма.ВладелецФормы.Объект.СпецификацияПанелей.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, СтруктураНовойСтроки);
    ЭтаФорма.Закрыть();
КонецПроцедуры

Почему этот подход считается плохой практикой и от него нужно отказаться?

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

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

Способ 1: Использование ОписаниеОповещения (Асинхронный вызов при закрытии)

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

Посмотрим на пример реализации кода в основной форме документа (откуда мы вызываем помощника):


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

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

Теперь выясним, как должен выглядеть код в форме помощника. Наша задача — собрать введенные пользователем данные в структуру и вернуть их при закрытии формы:


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

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

Способ 2: Использование ОповеститьОВыборе (Паттерн "Подбор")

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

Реализуем код в форме помощника:


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

В основной форме документа нам не нужно создавать никаких ОписаниеОповещения. Достаточно просто открыть помощник (обязательно указав владельца!) и переопределить стандартное событие формы:


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

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

Способ 3: Временное хранилище (Для передачи больших объемов данных)

Усложним задачу. Что если в форме-помощнике пользователь по нажатию одной кнопки генерирует не одну строку, а сложную спецификацию на 1000 строк? Формировать огромный массив структур и гонять его между клиентом и сервером крайне неэффективно: это вызовет задержки и перерасход оперативной памяти.

В таких случаях мы применим механизм Временного Хранилища. Разберем логику:

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

Посмотрим на пример кода в форме помощника:


&НаКлиенте
Процедура ЗавершитьИПеренестиДанные(Команда)
    // Получаем адрес во временном хранилище
    АдресДанных = ПодготовитьДанныеНаСервере(УникальныйИдентификатор);
    
    // Закрываем форму и возвращаем только строку с адресом
    ЭтаФорма.Закрыть(АдресДанных);
КонецПроцедуры

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

Теперь обработаем этот адрес в основной форме:


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

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

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

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

← На главную