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

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

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

Разбор типичной ошибки: почему ПолучитьФорму не работает для передачи данных

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

Форма1 = Формы.ПолучитьФорму("ОбщаяФорма.Форма1");

Значение = Форма1.Сотрудник;

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

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

Способ 1: Использование параметров формы (рекомендуемый подход)

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

Шаг 1. Подготовка во второй форме. В дереве реквизитов формы (Форма2) перейдем на закладку Параметры и добавим новый параметр, например, ФилиалСотрудника. Укажем ему соответствующий тип (например, СправочникСсылка.Филиалы).

Шаг 2. Вызов из первой формы. В обработчике команды открытия в Форме1 напишем код передачи параметров:


&НаКлиенте
Процедура ОткрытьФорму2(Команда)
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("ФилиалСотрудника", Объект.Филиал);
    
    ОткрытьФорму("ОбщаяФорма.Форма2", ПараметрыОткрытия);
КонецПроцедуры

Шаг 3. Прием данных во второй форме. В модуле Формы2 используем обработчик ПриСозданииНаСервере, чтобы прочитать переданное значение:


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

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

Способ 2: Использование владельца формы

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

Рассмотрим пример реализации:


// В Форме1 (открывающей)
&НаКлиенте
Процедура ОткрытьФормуСВладельцем()
    // ЭтаФорма становится владельцем новой формы
    ОткрытьФорму("ОбщаяФорма.Форма2", , ЭтаФорма);
КонецПроцедуры

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

Способ 3: Оповещения (механизм Оповестить и ОбработкаОповещения)

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

Проанализируем ситуацию: нам нужно передать филиал, как только его выбрали в Форме1.

В Форме1 пишем:


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

В Форме2 создаем обработчик события ОбработкаОповещения (выбирается в свойствах самой формы):


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

Этот метод крайне удобен для синхронизации нескольких открытых окон в интерфейсе "Такси".

Способ 4: Передача больших объемов данных через временное хранилище

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

Разберем правильный алгоритм:

  1. В первой форме на сервере помещаем данные во временное хранилище.
  2. Получаем адрес (строку).
  3. Передаем этот адрес как обычный параметр во вторую форму.
  4. Во второй форме на сервере извлекаем данные по адресу.

Пример кода для Формы1:


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

&НаКлиенте
Процедура ОткрытьСБольшимиДанными()
    АдресХранилища = ПодготовитьДанныеДляПередачи();
    ПараметрыФормы = Новый Структура("АдресДанных", АдресХранилища);
    ОткрытьФорму("ОбщаяФорма.Форма2", ПараметрыФормы);
КонецПроцедуры

Во второй форме в ПриСозданииНаСервере:


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

Способ 5: Вызов экспортных методов формы

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

В модуле Формы2:


&НаКлиенте
Процедура УстановитьФилиал(ЗначениеФилиала) Экспорт
    Объект.Филиал = ЗначениеФилиала;
КонецПроцедуры

В Форме1:


&НаКлиенте
Процедура ОткрытьЧерезМетод()
    НоваяФорма = ПолучитьФорму("ОбщаяФорма.Форма2");
    НоваяФорма.УстановитьФилиал(Объект.Филиал);
    НоваяФорма.Открыть();
КонецПроцедуры

Важный нюанс: при таком подходе процедура ПриСозданииНаСервере во второй форме отработает в момент вызова ПолучитьФорму, а экспортный метод УстановитьФилиал — после. Это нужно учитывать при проектировании логики.

Рекомендации по выбору метода

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

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

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

← На главную