При разработке в среде 1С:Предприятие часто возникает необходимость сохранять сложные типы данных — например, объекты Шрифт или Цвет — в реквизитах справочников или документов. Для этого используется тип данных ХранилищеЗначения. Однако разработчики нередко сталкиваются с ситуацией, когда данные в хранилище не сохраняются, и при повторном открытии формы реквизит оказывается пустым.
В этой статье мы подробно проанализируем причины этой проблемы, разберем жизненный цикл событий управляемой формы и рассмотрим корректные способы записи и считывания данных из ХранилищаЗначения.
Главная причина, по которой значение не записывается при вызове процедуры ПриЗаписиНаСервере, заключается в порядке выполнения событий платформы 1С при сохранении объекта.
Рассмотрим последовательность действий платформы при записи элемента из управляемой формы:
ПередЗаписьюНаСервере. В этот момент параметр ТекущийОбъект содержит копию данных, которая непосредственно перед помещением в транзакцию записи доступна для модификации.ТекущийОбъект в базу данных СУБД.ПриЗаписиНаСервере. К этому моменту объект уже записан в базу данных. Любые изменения реквизитов ТекущийОбъект в этой процедуре просто игнорируются платформой и не попадают в БД.Таким образом, модифицировать реквизиты объекта (включая реквизиты типа ХранилищеЗначения) в процедуре ПриЗаписиНаСервере слишком поздно.
Правильный подход к работе с реквизитами типа ХранилищеЗначения в управляемой форме заключается в следующем:
ТекущийОбъект выполняется строго в процедуре ПередЗаписьюНаСервере.ПриЧтенииНаСервере.Рассмотрим пример кода на сервере:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Замещаем хранилище новым значением до момент записи в БД
ТекущийОбъект.Шрифт = Новый ХранилищеЗначения(Шрифт);
ТекущийОбъект.ЦветФона = Новый ХранилищеЗначения(ЦветФона);
ТекущийОбъект.ЦветТекста = Новый ХранилищеЗначения(ЦветТекста);
КонецПроцедуры
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Восстанавливаем данные из хранилища при чтении объекта из БД
Если ЗначениеЗаполнено(ТекущийОбъект.Шрифт) Тогда
Шрифт = ТекущийОбъект.Шрифт.Получить();
КонецЕсли;
Если ЗначениеЗаполнено(ТекущийОбъект.ЦветФона) Тогда
ЦветФона = ТекущийОбъект.ЦветФона.Получить();
КонецЕсли;
Если ЗначениеЗаполнено(ТекущийОбъект.ЦветТекста) Тогда
ЦветТекста = ТекущийОбъект.ЦветТекста.Получить();
КонецЕсли;
КонецПроцедуры
При работе с реквизитами типа ХранилищеЗначения необходимо учитывать спецификацию управляемого приложения 1С:
Объект типа ДанныеФормыСтруктура) реквизиты с этим типом не содержат бинарных данных. Обращаться к ним напрямую на клиенте нельзя. Работа с ними должна вестись через реквизиты формы соответствующих типов (например, реквизит формы Шрифт с типом Шрифт).Шрифт или Цвет получено из системных настроек или темы оформления, при попытке помещения его в ХранилищеЗначения платформа может записать неполный объект. Чтобы избежать этого, создавайте абсолютные объекты, например: Новый Шрифт("Arial", 10, Истина) или Новый Цвет(255, 0, 0).ПоместитьВоВременноеХранилище(), а уже в процедуре ПередЗаписьюНаСервере извлекать эти данные через ПолучитьИзВременногоХранилища() и записывать в реквизит объекта.Если задача заключается только в сохранении настроек оформления (например, полужирный шрифт, размер, цвет), отличной альтернативой ХранилищуЗначения служит декомпозиция на примитивные реквизиты объекта или сериализация в строку:
ИмяШрифта (Строка), РазмерШрифта (Число), ШрифтBold (Булево). Это упрощает отбор и просмотр данных в СУБД, так как данные из ХранилищаЗначения недоступны в запросах.Строка неограниченной длины с помощью вызовов СериализаторXDTO.ЗаписатьXML() и СериализаторXDTO.ПрочитатьXML().