Часто при разработке на платформе 1С:Предприятие (особенно в управляемых формах) возникает типичная задача: есть основная форма, на которой расположен табличный документ для вывода отчета, и есть подчиненная (дополнительная) форма для ввода новых данных пользователем. Проанализируем ситуацию, с которой сталкиваются многие начинающие разработчики: попытка напрямую обратиться из второй формы к табличному документу первой формы приводит к ошибке «Переменная не определена». Рассмотрим подробнее, почему это происходит и как правильно спроектировать такое взаимодействие.
Выясним причину этой проблемы. В архитектуре управляемых форм 1С контексты разных форм строго изолированы друг от друга. Вторая форма ничего не знает о существовании реквизитов (например, поля Сотрудники или табличного документа) на первой форме. Более того, попытки передать макет или сам табличный документ во вторую форму для заполнения — это нарушение логики работы платформы.
Правильный алгоритм действий выглядит так:
ТаблицаЗначений. Это позволяет накапливать строки с информацией.Разберем по шагам реализацию этого механизма.
Вторая форма не должна заниматься формированием макетов или расчетом итогов. Ее задача — собрать ввод пользователя и отправить его инициатору открытия (главной форме).
Посмотрим на пример. Предположим, у нас есть поля ввода ФИО, Должность и Оклад. При нажатии на кнопку «Добавить» на второй форме, мы сформируем структуру и передадим ее с помощью метода Закрыть():
&НаКлиенте
Процедура КомандаДобавитьСотрудника(Команда)
ДанныеСотрудника = Новый Структура;
ДанныеСотрудника.Вставить("ФИО", ФИО);
ДанныеСотрудника.Вставить("Должность", Должность);
ДанныеСотрудника.Вставить("Оклад", Оклад);
// Закрываем текущую форму и передаем структуру в форму-владелец
ЭтаФорма.Закрыть(ДанныеСотрудника);
КонецПроцедуры
Если же бизнес-процесс требует вводить несколько сотрудников подряд без закрытия формы, вместо метода Закрыть() следует использовать глобальное оповещение с помощью метода Оповестить():
&НаКлиенте
Процедура КомандаДобавитьСотрудника(Команда)
// ... создание структуры ...
Оповестить("ДобавленНовыйСотрудник", ДанныеСотрудника);
КонецПроцедуры
Теперь перейдем в модуль первой (главной) формы. Нам нужно создать реквизит формы с типом ТаблицаЗначений (назовем его, например, ТаблицаСотрудников), в котором будут колонки: ФИО, Должность, Оклад.
Если мы использовали метод Закрыть() с передачей параметра, то ловить эти данные нужно в стандартном обработчике события формы ОбработкаВыбора:
&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора)
Если ТипЗнч(ВыбранноеЗначение) = Тип("Структура") Тогда
// Добавляем данные в таблицу значений на форме
НоваяСтрока = ТаблицаСотрудников.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ВыбранноеЗначение);
// Переформировываем табличный документ
ОбновитьТабличныйДокументНаСервере();
КонецЕсли;
КонецПроцедуры
Если мы использовали Оповестить(), то данные принимаются в обработчике ОбработкаОповещения, код внутри будет аналогичным.
Самое важное правило: макет — это лишь шаблон, а табличный документ — это конечный результат. Не пытайтесь искать и складывать цифры в ячейках самого табличного документа. У нас уже есть ТаблицаЗначений, и мы можем использовать всю мощь ее встроенных методов.
Чтобы получить сумму всех окладов, нам не нужен цикл. Достаточно использовать метод Итог(). Посмотрим, как выглядит итоговая процедура формирования печатной формы на сервере:
&НаСервере
Процедура ОбновитьТабличныйДокументНаСервере()
// Получаем реквизит формы типа ТабличныйДокумент
ТабДок = ЭтаФорма.СотрудникиТабДок;
// Обязательно очищаем перед новым заполнением!
ТабДок.Очистить();
// Получаем макет из объекта обработки/отчета
Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
ОбластьПодвал = Макет.ПолучитьОбласть("Подвал");
// 1. Выводим шапку
ТабДок.Вывести(ОбластьШапка);
// 2. Выводим строки в цикле по нашей накопленной Таблице Значений
Для Каждого СтрокаТЗ Из ЭтаФорма.ТаблицаСотрудников Цикл
ОбластьСтрока.Параметры.Заполнить(СтрокаТЗ);
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
// 3. Считаем итоги и выводим подвал
ИтоговыйОклад = ЭтаФорма.ТаблицаСотрудников.Итог("Оклад");
// Передаем подсчитанный итог в параметр подвала
ОбластьПодвал.Параметры.ИтогоОклад = ИтоговыйОклад;
ТабДок.Вывести(ОбластьПодвал);
КонецПроцедуры
Мы проанализировали правильную цепочку взаимодействия управляемых форм. Запомните ключевые правила:
Закрыть() или через событие Оповестить().ТаблицаЗначений. Это позволяет легко использовать методы вроде Итог() для расчетов без лишних циклов.Очистить() и перерисовывайте его заново на основе таблицы значений на стороне сервера (&НаСервере).Применяя этот подход, вы навсегда избавитесь от ошибок передачи контекста и сделаете свой код масштабируемым и легко читаемым.