При работе с обычными формами в 1С:Предприятие 8 программисты часто сталкиваются с тем, что архитектура «старого» типа форм существенно отличается от управляемого приложения. Одной из типовых проблем является сохранение сформированного ТабличногоДокумента. Если в управляемых формах мы можем использовать реквизит формы с типом ТабличныйДокумент, то в обычных формах такого типа данных для реквизитов просто не существует. В этой статье мы подробно разберем, как обойти это ограничение, используя ХранилищеЗначения, и как правильно организовать процесс записи и восстановления данных.
Для начала давайте разберем ситуацию, с которой столкнулся автор вопроса. В обычных формах элементы управления (визуальные объекты на форме) и данные (реквизиты объекта или формы) разделены более жестко. Вы можете вставить на форму элемент управления Поле табличного документа через меню Форма — Вставить элемент управления, но вы не найдете возможности привязать его к реквизиту объекта с тем же типом в метаданных.
Это связано с тем, что ТабличныйДокумент — это сложный объект, содержащий форматирование, картинки, расшифровки и области. Он не предназначен для прямого хранения в полях таблиц SQL в «сыром» виде. Поэтому для его сохранения нам потребуется промежуточный контейнер.
Самый надежный и правильный способ сохранить табличный документ, привязав его к конкретному документу или справочнику — это создание реквизита с типом ХранилищеЗначения. Рассмотрим этот процесс пошагово.
Шаг 1. Добавление реквизита в метаданные
Откройте конфигуратор, найдите нужный вам объект (например, справочник или документ) и добавьте новый реквизит. Назовем его ДанныеПечатнойФормы. В качестве типа данных выберите ХранилищеЗначения.
Шаг 2. Программная запись данных
Поскольку мы не можем напрямую связать поле на форме с этим реквизитом, нам нужно прописать код сохранения в модуле формы или объекта. Проанализируем пример кода для сохранения данных перед записью объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Получаем объект ТабличныйДокумент из элемента управления на форме
ТабДок = ЭлементыФормы.ПолеТабличногоДокумента.Значение;
// Помещаем его в ХранилищеЗначения с максимальным сжатием
// Сжатие данных (уровень 9) критически важно для экономии места в базе
ЭтотОбъект.ДанныеПечатнойФормы = Новый ХранилищеЗначения(ТабДок, Новый СжатиеДанных(9));
КонецПроцедуры
Использование СжатиеДанных(9) позволяет уменьшить размер хранимых данных в несколько раз, так как формат MXL по сути является XML-структурой, которая отлично сжимается.
Шаг 3. Восстановление данных при открытии формы
Теперь выясним, как вернуть данные обратно в поле формы при открытии. Лучше всего использовать обработчик ПриОткрытии или ПослеЗагрузкиДанныхИзОбъекта.
Процедура ПриОткрытии()
// Проверяем, не пустое ли хранилище
Если ЗначениеЗаполнено(ЭтотОбъект.ДанныеПечатнойФормы) Тогда
// Извлекаем ТабличныйДокумент из хранилища
СохраненныйТабДок = ЭтотОбъект.ДанныеПечатнойФормы.Получить();
// Проверяем, что в хранилище именно табличный документ
Если ТипЗнч(СохраненныйТабДок) = Тип("ТабличныйДокумент") Тогда
// Выводим данные в элемент управления на форме
ЭлементыФормы.ПолеТабличногоДокумента.Вывести(СохраненныйТабДок);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Рассмотрим альтернативную ситуацию: если вам не нужно хранить документ вечно в базе данных в привязке к конкретной записи, а нужно сохранить состояние формы для конкретного пользователя (например, чтобы при следующем открытии отчет выглядел так же). В этом случае создавать реквизит в метаданных избыточно.
Мы можем использовать системный механизм ХранилищеОбщихНастроек. Это позволяет сохранять настройки в системных таблицах базы данных. Проанализируем, как это реализовать:
// Сохранение
КлючОбъекта = "МояСпециальнаяФорма_СохраненныйТабДок";
ХранилищеОбщихНастроек.Сохранить(КлючОбъекта, "ПечатнаяФорма", ЭлементыФормы.ПолеТабДока.Значение);
// Восстановление
ТабДок = ХранилищеОбщихНастроек.Загрузить(КлючОбъекта, "ПечатнаяФорма");
Если ТабДок <> Неопределено Тогда
ЭлементыФормы.ПолеТабДока.Значение = ТабДок;
КонецЕсли;
При работе с ХранилищемЗначения начинающие разработчики часто беспокоятся о том, что база данных будет «тормозить» из-за тяжелых объектов. Давайте выясним, почему это не совсем так:
ХранилищеЗначения не считывается в оперативную память автоматически. Данные подгружаются только в тот момент, когда вы вызываете метод .Получить().ТабличныйДокумент на форме потребляет ресурсы клиентского приложения. Если документов очень много и они огромные (десятки тысяч строк), старайтесь не хранить их все одновременно открытыми в оперативной памяти.Разберем еще один практический момент. Если вы сохраняете табличный документ как «слепок» истории (например, архивный вариант счета на оплату), крайне важно после загрузки защитить его от случайных правок пользователя. В обычных формах это делается программно:
ЭлементыФормы.ПолеТабличногоДокумента.ТолькоПросмотр = Истина;
ЭлементыФормы.ПолеТабличногоДокумента.Защита = Истина;
Свойство Защита предотвращает редактирование ячеек, даже если пользователь попытается войти в режим редактирования через контекстное меню. Это гарантирует, что данные в базе будут соответствовать тому, что видит пользователь на экране.
Иногда возникают задачи передачи ТабличногоДокумента между разными информационными базами или через веб-сервисы. В этом случае ХранилищеЗначения может быть неудобно. Мы можем преобразовать документ в строку XML и сохранить её как обычный текст. Посмотрим на пример кода:
// Преобразование в XML-строку
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ЭлементыФормы.ПолеТабДока.Значение);
XMLСтрокаДанных = ЗаписьXML.Закрыть();
// Чтение из XML-строки
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(XMLСтрокаДанных);
ТабДок = СериализаторXDTO.ПрочитатьXML(ЧтениеXML, Тип("ТабличныйДокумент"));
Этот метод более трудоемкий, но он дает полный контроль над данными и позволяет сохранять табличный документ даже в обычные строковые реквизиты (хотя это и не рекомендуется из-за ограничений на длину строки).
Подводя итог, можно сказать, что отсутствие типа ТабличныйДокумент в реквизитах обычных форм — это не препятствие, а особенность архитектуры. Использование ХранилищаЗначения в сочетании с программным выводом через ЭлементыФормы является стандартным и наиболее эффективным решением для задач сохранения печатных форм и сложных отчетов.