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