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

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

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

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

Способ 1. Прямой вызов методов владельца (для Обычных форм)

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

Выполним эту задачу по шагам:

  1. В модуле основной формы документа объявим нужную функцию с ключевым словом Экспорт. Это сделает её доступной извне.
  2. Во вспомогательной форме при ее открытии укажем владельца (обычно это происходит автоматически, если форма открывается из контекста основной, либо передается параметром в метод ПолучитьФорму).
  3. Внутри вспомогательной формы вызовем экспортную функцию через точку от свойства ВладелецФормы.

Рассмотрим пример кода в основной форме документа:


// В модуле основной формы документа
Функция ВыполнитьРасчетНаОснованииДанных(ИДСпуска, ТаблицаПараметров) Экспорт
    // Здесь выполняется сложный поиск по локальным переменным формы
    // Например, поиск по табличной части "Листы"
    НайтиЛист = Листы.НайтиСтроки(Новый Структура("ИДЛиста", ИДСпуска));
    Если НайтиЛист.Количество() > 0 Тогда
        Возврат НайтиЛист[0].ПечатнаяМашинаЛицо;
    КонецЕсли;
    Возврат Неопределено;
КонецФункции

Теперь проанализируем, как вызвать эту функцию из модуля произвольной (вспомогательной) формы:


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

Способ 2. Использование ОписанияОповещения (для Управляемых форм)

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

Для реализации гибкого и независимого вызова по стандартам разработки 1С используется механизм обратного вызова (Callback) с помощью объекта ОписаниеОповещения. Давайте разберем этот паттерн:

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


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

&НаКлиенте
Процедура ПослеЗакрытияВспомогательнойФормы(РезультатВыбора, ДополнительныеПараметры) Экспорт
    Если РезультатВыбора <> Неопределено Тогда
        // Здесь мы получаем данные из вспомогательной формы и запускаем расчет основной формы
        ВыполнитьЛокальныйРасчетНаОснованииДанных(РезультатВыбора);
    КонецЕсли;
КонецПроцедуры

Внутри вспомогательной формы нам не нужно знать ничего о структуре основной формы. Мы просто возвращаем результат расчетов при закрытии:


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

Способ 3. Перенос расчетной логики в Модуль Менеджера (Рефакторинг)

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

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

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

Пример реализации функции в модуле менеджера документа:


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

Теперь из любой формы (хоть из основной, хоть из произвольной вспомогательной) вы можете легко вызвать этот метод:


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

Способ 4. Передача Таблиц Значений между формами

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

В обычных формах:

Поскольку в обычном приложении весь код выполняется на клиенте в одном контексте, мы можем передавать тип ТаблицаЗначений напрямую, например, упаковав несколько таблиц в Массив или Структура:


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

В управляемых формах (через Временное хранилище):

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


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

// 2. Передаем полученный Адрес во вспомогательную форму в качестве параметра при открытии

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

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

← На главную