Как записать и сохранить табличный документ на обычной форме в 1С

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

При работе с обычными формами в 1С:Предприятие 8 программисты часто сталкиваются с тем, что архитектура «старого» типа форм существенно отличается от управляемого приложения. Одной из типовых проблем является сохранение сформированного ТабличногоДокумента. Если в управляемых формах мы можем использовать реквизит формы с типом ТабличныйДокумент, то в обычных формах такого типа данных для реквизитов просто не существует. В этой статье мы подробно разберем, как обойти это ограничение, используя ХранилищеЗначения, и как правильно организовать процесс записи и восстановления данных.

Анализ проблемы: почему типа данных ТабличныйДокумент нет в реквизитах

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

Это связано с тем, что ТабличныйДокумент — это сложный объект, содержащий форматирование, картинки, расшифровки и области. Он не предназначен для прямого хранения в полях таблиц SQL в «сыром» виде. Поэтому для его сохранения нам потребуется промежуточный контейнер.

Решение 1: Использование ХранилищаЗначения в метаданных объекта

Самый надежный и правильный способ сохранить табличный документ, привязав его к конкретному документу или справочнику — это создание реквизита с типом ХранилищеЗначения. Рассмотрим этот процесс пошагово.

Шаг 1. Добавление реквизита в метаданные

Откройте конфигуратор, найдите нужный вам объект (например, справочник или документ) и добавьте новый реквизит. Назовем его ДанныеПечатнойФормы. В качестве типа данных выберите ХранилищеЗначения.

Шаг 2. Программная запись данных

Поскольку мы не можем напрямую связать поле на форме с этим реквизитом, нам нужно прописать код сохранения в модуле формы или объекта. Проанализируем пример кода для сохранения данных перед записью объекта:


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

Использование СжатиеДанных(9) позволяет уменьшить размер хранимых данных в несколько раз, так как формат MXL по сути является XML-структурой, которая отлично сжимается.

Шаг 3. Восстановление данных при открытии формы

Теперь выясним, как вернуть данные обратно в поле формы при открытии. Лучше всего использовать обработчик ПриОткрытии или ПослеЗагрузкиДанныхИзОбъекта.


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

Решение 2: Использование ХранилищаОбщихНастроек

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

Мы можем использовать системный механизм ХранилищеОбщихНастроек. Это позволяет сохранять настройки в системных таблицах базы данных. Проанализируем, как это реализовать:


// Сохранение
КлючОбъекта = "МояСпециальнаяФорма_СохраненныйТабДок";
ХранилищеОбщихНастроек.Сохранить(КлючОбъекта, "ПечатнаяФорма", ЭлементыФормы.ПолеТабДока.Значение);

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

Важные нюансы производительности и памяти

При работе с ХранилищемЗначения начинающие разработчики часто беспокоятся о том, что база данных будет «тормозить» из-за тяжелых объектов. Давайте выясним, почему это не совсем так:

  1. Ленивая загрузка: Платформа 1С работает оптимизировано. Когда вы выбираете данные запросом или открываете список документов, содержимое реквизитов типа ХранилищеЗначения не считывается в оперативную память автоматически. Данные подгружаются только в тот момент, когда вы вызываете метод .Получить().
  2. Эффективность сжатия: Как мы уже упоминали, табличные документы очень хорошо сжимаются. Документ, который в формате PDF весит 1 Мб, в сжатом хранилище может занимать всего несколько десятков килобайт.
  3. Очистка памяти: Не забывайте, что ТабличныйДокумент на форме потребляет ресурсы клиентского приложения. Если документов очень много и они огромные (десятки тысяч строк), старайтесь не хранить их все одновременно открытыми в оперативной памяти.

Особенности отображения: свойство ТолькоПросмотр

Разберем еще один практический момент. Если вы сохраняете табличный документ как «слепок» истории (например, архивный вариант счета на оплату), крайне важно после загрузки защитить его от случайных правок пользователя. В обычных формах это делается программно:


ЭлементыФормы.ПолеТабличногоДокумента.ТолькоПросмотр = Истина;
ЭлементыФормы.ПолеТабличногоДокумента.Защита = Истина;

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

Сериализация в XML (Альтернативный взгляд)

Иногда возникают задачи передачи ТабличногоДокумента между разными информационными базами или через веб-сервисы. В этом случае ХранилищеЗначения может быть неудобно. Мы можем преобразовать документ в строку XML и сохранить её как обычный текст. Посмотрим на пример кода:


// Преобразование в XML-строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ЭлементыФормы.ПолеТабДока.Значение);
XMLСтрокаДанных = ЗаписьXML.Закрыть();

// Чтение из XML-строки
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(XMLСтрокаДанных);
ТабДок = СериализаторXDTO.ПрочитатьXML(ЧтениеXML, Тип("ТабличныйДокумент"));

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

Подводя итог, можно сказать, что отсутствие типа ТабличныйДокумент в реквизитах обычных форм — это не препятствие, а особенность архитектуры. Использование ХранилищаЗначения в сочетании с программным выводом через ЭлементыФормы является стандартным и наиболее эффективным решением для задач сохранения печатных форм и сложных отчетов.

← На главную