Как передать ТаблицуЗначений между серверными функциями формы в 1С:Предприятие 8.3?

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

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

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

Почему возникают проблемы с передачей ТаблицыЗначений?

Основная причина потери данных кроется в понимании жизненного цикла и области видимости (scope) переменных в 1С. Когда мы объявляем переменную внутри конкретной процедуры или функции на сервере, она является локальной. Это означает, что она существует только на время выполнения этой процедуры/функции. Как только процедура завершает свою работу, все ее локальные переменные "умирают", и их значения теряются.

Например, если мы создадим ТаблицуЗначений в процедуре ПриСозданииНаСервере() и присвоим ее локальной переменной, после завершения этой процедуры переменная и ее содержимое будут уничтожены. При последующем вызове другого серверного обработчика (например, ОбработкаРасшифровки()), эта локальная переменная уже не будет существовать, и мы не сможем получить к ней доступ.

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

Решение 1: Использование свойства "Расшифровка" табличного документа

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

  1. Суть метода: Мы можем "привязать" произвольное значение к каждой ячейке или области табличного документа с помощью свойства Расшифровка. При клике на эту ячейку, в обработчик события будет передано именно это значение, что позволяет нам получить контекстные данные без необходимости хранить всю ТаблицуЗначений в реквизитах формы.
  2. Когда применять: Этот метод особенно эффективен, если ваша ТаблицаЗначений содержит информацию, которую вы хотите ассоциировать с визуальным представлением в табличном документе (например, координаты ячейки, время, ссылка на объект).
  3. Пошаговая реализация:
  4. Сначала, в процедуре, где мы формируем табличный документ (например, ПриСозданииНаСервере или в любой другой серверной процедуре, отвечающей за вывод отчета), мы заполняем свойство Расшифровка для каждой нужной ячейки или области. Например, если мы выводим расписание и хотим связать каждую ячейку со временем:

    
    &НаСервере
    Процедура ПриСозданииНаСервере(Отказ)
        // Получаем табличный документ с формы
        ТабДок = Элементы.ПолеТабличногоДокумента.Получить(); 
            
        // Пример формирования областей и присвоения расшифровки
        // Предположим, у нас есть данные о днях недели и времени
        // Для примера создадим простую ТаблицуЗначений
        Перем ТаблицаРасписания;
        ТаблицаРасписания = Новый ТаблицаЗначений;
        ТаблицаРасписания.Колонки.Добавить("Адрес");
        ТаблицаРасписания.Колонки.Добавить("Время");
            
        ТаблицаРасписания.Добавить().Заполнить(Новый Соответствие("Адрес", "R1C1", "Время", "9:00"));
        ТаблицаРасписания.Добавить().Заполнить(Новый Соответствие("Адрес", "R1C2", "Время", "10:00"));
        ТаблицаРасписания.Добавить().Заполнить(Новый Соответствие("Адрес", "R2C1", "Время", "11:00"));
            
        // Область для вывода данных
        Для Каждого СтрокаТЗ Из ТаблицаРасписания Цикл
            // В реальной ситуации мы будем использовать шаблон или создавать области динамически
            // Здесь для простоты используем адреса R1C1, R1C2 и т.д.
            АдресЯчейки = СтрокаТЗ.Адрес; // Например, "R1C1"
                
            // Если область не существует, можно ее создать или вывести данные в конкретную ячейку
            Попытка
                ЯчейкаОбласть = ТабДок.Область(АдресЯчейки);
            Исключение
                // Если ячейки нет, создадим ее для примера
                // В реальной жизни ТабДок уже должен быть сформирован
                // Например, ТабДок.ВывестиСекцию("МояСекция"); и затем работаем с выведенной областью
                ТабДок.ПоместитьТекст(СтрокаТЗ.Время, ТабДок.ВысотаТаблицы, 1); // Просто для демонстрации, реальное формирование сложнее
                ЯчейкаОбласть = ТабДок.Область(ТабДок.ВысотаТаблицы, 1);
            КонецПопытки;
                
            ЯчейкаОбласть.Текст = СтрокаТЗ.Время; // Видимый текст в ячейке
            ЯчейкаОбласть.Расшифровка = СтрокаТЗ.Время; // Здесь мы привязываем само время или любой другой идентификатор
            // Можно также передать структуру или соответствие, если нужно несколько значений:
            // ЯчейкаОбласть.Расшифровка = Новый Структура("Адрес, Время", СтрокаТЗ.Адрес, СтрокаТЗ.Время);
        КонецЦикла;
            
        // Отображаем табличный документ на форме
        Элементы.ПолеТабличногоДокумента.ОбновитьОтображение();
    КонецПроцедуры
    

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

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

Решение 2: Использование реквизита формы с типом "ТаблицаЗначений"

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

  1. Суть метода: Мы создаем специальный реквизит непосредственно в свойствах формы. Этот реквизит будет "жить" столько же, сколько и сама форма, и его значение будет доступно из любой серверной процедуры или функции этой формы.
  2. Когда применять: Используйте этот метод, если ТаблицаЗначений нужна вам для различных операций, не только для обработки выбора ячейки (например, для фильтрации, поиска, дальнейшей обработки данных целиком).
  3. Пошаговая реализация:
  4. Шаг 1: Создание реквизита формы.

    Откройте форму в конфигураторе. На вкладке "Реквизиты" формы добавьте новый реквизит. Укажите его имя (например, МояТаблицаЗначенийНаФорме) и самое главное — установите его Тип как ТаблицаЗначений. Очень важно не использовать "Произвольный" тип, так как это может приводить к проблемам с сериализацией и потерей типа данных при передаче.

    Шаг 2: Присвоение ТаблицыЗначений реквизиту формы.

    В той серверной процедуре, где вы формируете ТаблицуЗначений (например, ПриСозданииНаСервере), присвойте ее созданному реквизиту формы. Это делается так:

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

    Шаг 3: Доступ к ТаблицеЗначений из другой серверной процедуры.

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

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

Решение 3: Переменные уровня модуля формы с модификатором &НаСервере

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

  1. Суть метода: Мы объявляем переменную не внутри какой-то конкретной процедуры, а на уровне всего модуля формы. При этом обязательно указываем модификатор &НаСервере, чтобы переменная существовала в серверном контексте и сохраняла свое значение между серверными вызовами для данной формы.
  2. Когда применять: Этот метод удобен для хранения служебных данных, которые используются только в логике формы на сервере и не являются частью ее постоянных атрибутов.
  3. Пошаговая реализация:
  4. Шаг 1: Объявление переменной уровня модуля.

    В самом начале модуля формы, до всех процедур и функций, объявите вашу переменную с модификатором &НаСервере:

    Перем МояТаблицаЗначенийМодуля &НаСервере;

    Шаг 2: Присвоение ТаблицыЗначений переменной модуля.

    Как и в случае с реквизитом формы, присваиваем ТаблицуЗначений этой переменной в процедуре, где она формируется:

    
    &НаСервере
    Процедура ПриСозданииНаСервере(Отказ)
        // Создаем и заполняем ТаблицуЗначений
        Перем ТаблицаДляМодуля;
        ТаблицаДляМодуля = Новый ТаблицаЗначений;
        ТаблицаДляМодуля.Колонки.Добавить("Код");
        ТаблицаДляМодуля.Колонки.Добавить("Описание");
            
        ТаблицаДляМодуля.Добавить().Заполнить(Новый Соответствие("Код", 1, "Описание", "Элемент 1"));
        ТаблицаДляМодуля.Добавить().Заполнить(Новый Соответствие("Код", 2, "Описание", "Элемент 2"));
            
        // Присваиваем ТаблицуЗначений переменной уровня модуля
        МояТаблицаЗначенийМодуля = ТаблицаДляМодуля;
            
        // Сообщить("Таблица значений успешно сохранена в переменной модуля. Количество строк: " + МояТаблицаЗначенийМодуля.Количество());
    КонецПроцедуры
    

    Шаг 3: Доступ к ТаблицеЗначений из другой серверной процедуры.

    В любой другой серверной процедуре или функции этой формы вы можете обращаться к МояТаблицаЗначенийМодуля напрямую:

    
    &НаСервере
    Процедура ОбработкаКнопкиНаСервере()
        Если МояТаблицаЗначенийМодуля <> Неопределено И МояТаблицаЗначенийМодуля.Количество() > 0 Тогда
            Сообщить("Доступ к ТаблицеЗначений из переменной модуля. Первая строка: " + МояТаблицаЗначенийМодуля[0].Описание);
        Иначе
            Сообщить("ТаблицаЗначений в переменной модуля пуста или не определена.");
        КонецЕсли;
    КонецПроцедуры
    
  5. Важные моменты:
    • Модификатор &НаСервере критически важен. Без него переменная будет создана в клиентском контексте, и вы не сможете получить к ней доступ на сервере.
    • Эта переменная также привязана к конкретному экземпляру формы. Для каждого нового открытого окна формы будет свой экземпляр такой переменной.

Заключение

Мы рассмотрели три основных надежных способа передачи ТаблицыЗначений между серверными процедурами формы в 1С:Предприятие 8.3:

  1. Свойство Расшифровка табличного документа: Лучший выбор, когда данные привязаны к визуальным элементам табличного документа, и вам нужна информация о конкретном выбранном элементе. Это решение было использовано автором темы и успешно решило его проблему.
  2. Реквизит формы типа ТаблицаЗначений: Наиболее универсальный и рекомендуемый способ, если ТаблицаЗначений является частью данных формы и должна быть доступна целиком для различных операций на протяжении всего ее жизненного цикла.
  3. Переменная уровня модуля формы с модификатором &НаСервере: Удобный вариант для служебных данных, которые нужны во многих серверных функциях формы, но не являются ее официальными реквизитами.

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

← На главную