Как открыть свою форму и передать в неё табличную часть в 1С 8.3

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

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

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

Почему нельзя просто передать табличную часть напрямую?

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

Способ 1. Использование Временного Хранилища и параметров формы (Рекомендуемый)

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

Рассмотрим по шагам реализацию в вызывающей форме (например, в документе):


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

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

Теперь проанализируем, как принять эти данные в модуле нашей открываемой формы (в обработчике события ПриСозданииНаСервере):


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

Способ 2. Как вернуть измененные данные обратно в документ

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

Разберем, как вернуть данные с использованием метода ОповеститьОВыборе. В модуле вспомогательной формы при нажатии на кнопку «ОК» или «Перенести данные» пишем следующий код:


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

&НаКлиенте
Процедура ПеренестиДанные(Команда)
    
    АдресИзмененныхДанных = ПоместитьИзмененияВХранилище();
    
    // Оповещаем форму-владельца и передаем адрес с новыми данными
    ОповеститьОВыборе(АдресИзмененныхДанных);
    
    // Закрываем текущую форму
    Закрыть();
    
КонецПроцедуры

В форме документа (владельца) нам необходимо обработать этот выбор. Для этого определим обработчик события ОбработкаВыбора:


&НаКлиенте
Процедура ОбработкаВыбора(РезультатВыбора, ИсточникВыбора)
    
    // Проверяем, что к нам вернулся адрес временного хранилища
    Если ПолучитьНавигационнуюСсылкуИнформационнойБазы() <> Неопределено 
        И ЭтоАдресВременногоХранилища(РезультатВыбора) Тогда
        
        // Запускаем серверную процедуру для обновления табличной части
        ОбновитьТабличнуюЧастьНаСервере(РезультатВыбора);
        
        // Модифицируем форму, чтобы система поняла, что документ изменен
        ЭтаФорма.Модифицированность = Истина;
        
    КонецЕсли;
    
КонецПроцедуры

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

Способ 3. Передача данных без обращения к серверу (Массив структур)

Если ваша табличная часть небольшая (в пределах 100-200 строк), вы можете полностью избежать серверных вызовов при открытии формы. Для этого можно упаковать данные в массив структур на стороне клиента и передать его напрямую в параметрах формы.

Давайте посмотрим, как быстро собрать данные на клиенте:


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

В открываемой форме в процедуре ПриСозданииНаСервере мы легко распакуем данный массив:


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

Важный нюанс: Оптимизация работы через ЗначениеВРеквизитФормы

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


// Пример быстрого заполнения реквизита формы "Товары" из Таблицы Значений
ЗначениеВРеквизитФормы(ТаблицаДанных, "Объект.Товары");

И обратное быстрое преобразование реквизита формы в полноценную таблицу значений на сервере для последующего анализа или вычислений:

ТаблицаДляАнализа = РеквизитФормыВЗначение("Объект.Товары");

Использование данных методов существенно сокращает объем кода и ускоряет быстродействие конфигурации на крупных базах данных.

← На главную