При разработке управляемых форм в 1С:Предприятие 8.3 мы часто сталкиваемся с необходимостью передавать данные между различными серверными процедурами. Одним из таких сценариев является сбор данных в ТаблицуЗначений в одной серверной процедуре (например, при создании формы) и последующее использование этих данных в другой серверной процедуре, такой как обработчик события выбора элемента формы (например, клик по ячейке табличного документа).
Начинающие разработчики нередко сталкиваются с проблемой, когда собранная ТаблицаЗначений, казалось бы, сохраненная в реквизите формы или глобальной переменной, оказывается пустой или неопределенной при попытке доступа к ней из другой процедуры. Давайте разберем, почему так происходит, и какие существуют надежные способы решения этой задачи.
Основная причина потери данных кроется в понимании жизненного цикла и области видимости (scope) переменных в 1С. Когда мы объявляем переменную внутри конкретной процедуры или функции на сервере, она является локальной. Это означает, что она существует только на время выполнения этой процедуры/функции. Как только процедура завершает свою работу, все ее локальные переменные "умирают", и их значения теряются.
Например, если мы создадим ТаблицуЗначений в процедуре ПриСозданииНаСервере() и присвоим ее локальной переменной, после завершения этой процедуры переменная и ее содержимое будут уничтожены. При последующем вызове другого серверного обработчика (например, ОбработкаРасшифровки()), эта локальная переменная уже не будет существовать, и мы не сможем получить к ней доступ.
Для сохранения данных между различными серверными вызовами, связанными с одной и той же формой, нам необходимо использовать механизмы, которые обеспечивают их постоянство (персистентность) на протяжении всего жизненного цикла формы. Рассмотрим подробнее основные способы.
Этот способ идеально подходит, когда данные, которые мы хотим передать, связаны с конкретными ячейками или областями табличного документа, и нам нужно получить эти данные именно при интерактивном выборе пользователем (например, при клике).
Расшифровка. При клике на эту ячейку, в обработчик события будет передано именно это значение, что позволяет нам получить контекстные данные без необходимости хранить всю ТаблицуЗначений в реквизитах формы.Сначала, в процедуре, где мы формируем табличный документ (например, ПриСозданииНаСервере или в любой другой серверной процедуре, отвечающей за вывод отчета), мы заполняем свойство Расшифровка для каждой нужной ячейки или области. Например, если мы выводим расписание и хотим связать каждую ячейку со временем:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ)
// Получаем табличный документ с формы
ТабДок = Элементы.ПолеТабличногоДокумента.Получить();
// Пример формирования областей и присвоения расшифровки
// Предположим, у нас есть данные о днях недели и времени
// Для примера создадим простую ТаблицуЗначений
Перем ТаблицаРасписания;
ТаблицаРасписания = Новый ТаблицаЗначений;
ТаблицаРасписания.Колонки.Добавить("Адрес");
ТаблицаРасписания.Колонки.Добавить("Время");
ТаблицаРасписания.Добавить().Заполнить(Новый Соответствие("Адрес", "R1C1", "Время", "9:00"));
ТаблицаРасписания.Добавить().Заполнить(Новый Соответствие("Адрес", "R1C2", "Время", "10:00"));
ТаблицаРасписания.Добавить().Заполнить(Новый Соответствие("Адрес", "R2C1", "Время", "11:00"));
// Область для вывода данных
Для Каждого СтрокаТЗ Из ТаблицаРасписания Цикл
// В реальной ситуации мы будем использовать шаблон или создавать области динамически
// Здесь для простоты используем адреса R1C1, R1C2 и т.д.
АдресЯчейки = СтрокаТЗ.Адрес; // Например, "R1C1"
// Если область не существует, можно ее создать или вывести данные в конкретную ячейку
Попытка
ЯчейкаОбласть = ТабДок.Область(АдресЯчейки);
Исключение
// Если ячейки нет, создадим ее для примера
// В реальной жизни ТабДок уже должен быть сформирован
// Например, ТабДок.ВывестиСекцию("МояСекция"); и затем работаем с выведенной областью
ТабДок.ПоместитьТекст(СтрокаТЗ.Время, ТабДок.ВысотаТаблицы, 1); // Просто для демонстрации, реальное формирование сложнее
ЯчейкаОбласть = ТабДок.Область(ТабДок.ВысотаТаблицы, 1);
КонецПопытки;
ЯчейкаОбласть.Текст = СтрокаТЗ.Время; // Видимый текст в ячейке
ЯчейкаОбласть.Расшифровка = СтрокаТЗ.Время; // Здесь мы привязываем само время или любой другой идентификатор
// Можно также передать структуру или соответствие, если нужно несколько значений:
// ЯчейкаОбласть.Расшифровка = Новый Структура("Адрес, Время", СтрокаТЗ.Адрес, СтрокаТЗ.Время);
КонецЦикла;
// Отображаем табличный документ на форме
Элементы.ПолеТабличногоДокумента.ОбновитьОтображение();
КонецПроцедуры
Затем, когда пользователь кликает по ячейке, срабатывает событие ОбработкаРасшифровки табличного документа. В обработчике этого события мы можем получить то значение, которое мы записали в свойство Расшифровка:
&НаСервере
Процедура ПолеТабличногоДокументаОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
// Расшифровка содержит значение, которое мы присвоили в процедуре ПриСозданииНаСервере
Если ТипЗнч(Расшифровка) = Тип("Строка") Тогда
Сообщить("Выбранное время: " + Расшифровка);
// Далее мы можем использовать это значение, например, для открытия новой формы
ПараметрыОткрытия = Новый Структура("ВыбранноеВремя", Расшифровка);
ОткрытьФорму("ВашаФорма", ПараметрыОткрытия);
ИначеЕсли ТипЗнч(Расшифровка) = Тип("Структура") Тогда
// Если в расшифровку передавали структуру
Сообщить("Выбрана ячейка по адресу " + Расшифровка.Адрес + " со временем " + Расшифровка.Время);
ПараметрыОткрытия = Расшифровка;
ОткрытьФорму("ВашаФорма", ПараметрыОткрытия);
КонецЕсли;
СтандартнаяОбработка = Ложь; // Отменяем стандартную обработку, если наша логика достаточна
КонецПроцедуры
Это основной и наиболее универсальный способ хранения и передачи данных, включая ТаблицуЗначений, на протяжении всего жизненного цикла формы. Если вам нужна вся ТаблицаЗначений целиком в разных серверных процедурах формы, реквизит формы — это ваш выбор.
Шаг 1: Создание реквизита формы.
Откройте форму в конфигураторе. На вкладке "Реквизиты" формы добавьте новый реквизит. Укажите его имя (например, МояТаблицаЗначенийНаФорме) и самое главное — установите его Тип как ТаблицаЗначений. Очень важно не использовать "Произвольный" тип, так как это может приводить к проблемам с сериализацией и потерей типа данных при передаче.
Шаг 2: Присвоение ТаблицыЗначений реквизиту формы.
В той серверной процедуре, где вы формируете ТаблицуЗначений (например, ПриСозданииНаСервере), присвойте ее созданному реквизиту формы. Это делается так:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ)
// Создаем и заполняем ТаблицуЗначений
Перем ТаблицаДляФормы;
ТаблицаДляФормы = Новый ТаблицаЗначений;
ТаблицаДляФормы.Колонки.Добавить("Имя");
ТаблицаДляФормы.Колонки.Добавить("Значение");
ТаблицаДляФормы.Добавить().Заполнить(Новый Соответствие("Имя", "Параметр1", "Значение", 100));
ТаблицаДляФормы.Добавить().Заполнить(Новый Соответствие("Имя", "Параметр2", "Значение", "Текст"));
// Присваиваем ТаблицуЗначений реквизиту формы
// "МояТаблицаЗначенийНаФорме" - это имя реквизита формы, созданного на Шаге 1.
МояТаблицаЗначенийНаФорме = ТаблицаДляФормы;
// Сообщить("Таблица значений успешно сохранена в реквизите формы. Количество строк: " + МояТаблицаЗначенийНаФорме.Количество());
КонецПроцедуры
Шаг 3: Доступ к ТаблицеЗначений из другой серверной процедуры.
Теперь, в любой другой серверной процедуре или функции этой же формы (например, в обработчике кнопки, обработчике события поля формы, или том же ПолеТабличногоДокументаОбработкаРасшифровки), вы можете получить доступ к сохраненной ТаблицеЗначений через ее реквизит формы:
&НаСервере
Процедура ЛюбаяДругаяСервернаяПроцедура()
// Проверяем, что реквизит формы не пуст
Если МояТаблицаЗначенийНаФорме <> Неопределено И МояТаблицаЗначенийНаФорме.Количество() > 0 Тогда
Сообщить("Доступ к ТаблицеЗначений из другой процедуры. Количество строк: " + МояТаблицаЗначенийНаФорме.Количество());
// Пример использования: обход строк таблицы
Для Каждого СтрокаТЗ Из МояТаблицаЗначенийНаФорме Цикл
Сообщить("Имя: " + СтрокаТЗ.Имя + ", Значение: " + СтрокаТЗ.Значение);
КонецЦикла;
// Или поиск по таблице
СтрокаПоиска = МояТаблицаЗначенийНаФорме.Найти("Параметр1", "Имя");
Если СтрокаПоиска <> Неопределено Тогда
Сообщить("Найден параметр: " + СтрокаПоиска.Имя + " со значением: " + СтрокаПоиска.Значение);
КонецЕсли;
Иначе
Сообщить("ТаблицаЗначений в реквизите формы пуста или не определена.");
КонецЕсли;
КонецПроцедуры
ТаблицаЗначений. Использование "Произвольного" типа может приводить к непредсказуемым результатам из-за особенностей сериализации.ИмяРеквизитаФормы = ВашаТаблицаЗначений;.Этот способ является компромиссным между локальными переменными и реквизитами формы. Если вам нужно, чтобы ТаблицаЗначений была доступна во всех серверных процедурах и функциях одной формы, но вы не хотите создавать для нее реквизит формы (например, если она не связана напрямую с визуальным представлением данных формы), можно использовать переменные уровня модуля.
&НаСервере, чтобы переменная существовала в серверном контексте и сохраняла свое значение между серверными вызовами для данной формы.Шаг 1: Объявление переменной уровня модуля.
В самом начале модуля формы, до всех процедур и функций, объявите вашу переменную с модификатором &НаСервере:
Перем МояТаблицаЗначенийМодуля &НаСервере;
Шаг 2: Присвоение ТаблицыЗначений переменной модуля.
Как и в случае с реквизитом формы, присваиваем ТаблицуЗначений этой переменной в процедуре, где она формируется:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ)
// Создаем и заполняем ТаблицуЗначений
Перем ТаблицаДляМодуля;
ТаблицаДляМодуля = Новый ТаблицаЗначений;
ТаблицаДляМодуля.Колонки.Добавить("Код");
ТаблицаДляМодуля.Колонки.Добавить("Описание");
ТаблицаДляМодуля.Добавить().Заполнить(Новый Соответствие("Код", 1, "Описание", "Элемент 1"));
ТаблицаДляМодуля.Добавить().Заполнить(Новый Соответствие("Код", 2, "Описание", "Элемент 2"));
// Присваиваем ТаблицуЗначений переменной уровня модуля
МояТаблицаЗначенийМодуля = ТаблицаДляМодуля;
// Сообщить("Таблица значений успешно сохранена в переменной модуля. Количество строк: " + МояТаблицаЗначенийМодуля.Количество());
КонецПроцедуры
Шаг 3: Доступ к ТаблицеЗначений из другой серверной процедуры.
В любой другой серверной процедуре или функции этой формы вы можете обращаться к МояТаблицаЗначенийМодуля напрямую:
&НаСервере
Процедура ОбработкаКнопкиНаСервере()
Если МояТаблицаЗначенийМодуля <> Неопределено И МояТаблицаЗначенийМодуля.Количество() > 0 Тогда
Сообщить("Доступ к ТаблицеЗначений из переменной модуля. Первая строка: " + МояТаблицаЗначенийМодуля[0].Описание);
Иначе
Сообщить("ТаблицаЗначений в переменной модуля пуста или не определена.");
КонецЕсли;
КонецПроцедуры
&НаСервере критически важен. Без него переменная будет создана в клиентском контексте, и вы не сможете получить к ней доступ на сервере.Мы рассмотрели три основных надежных способа передачи ТаблицыЗначений между серверными процедурами формы в 1С:Предприятие 8.3:
Расшифровка табличного документа: Лучший выбор, когда данные привязаны к визуальным элементам табличного документа, и вам нужна информация о конкретном выбранном элементе. Это решение было использовано автором темы и успешно решило его проблему.ТаблицаЗначений: Наиболее универсальный и рекомендуемый способ, если ТаблицаЗначений является частью данных формы и должна быть доступна целиком для различных операций на протяжении всего ее жизненного цикла.&НаСервере: Удобный вариант для служебных данных, которые нужны во многих серверных функциях формы, но не являются ее официальными реквизитами.Выбирайте метод, который наиболее соответствует вашей задаче и архитектуре решения. Понимание жизненного цикла переменных и правильное использование механизмов платформы 1С поможет избежать многих ошибок и сделает ваш код более надежным и поддерживаемым.