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