Как работать с хранилищем значений в строках табличной части управляемой формы?

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

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

В чем заключается проблема и почему данные теряются

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

Если в табличной части прикладного объекта присутствует реквизит типа ХранилищеЗначения, то при чтении объекта и вызове механизма ЗначениеВРеквизитФормы эти реквизиты не передаются в строки таблицы формы. В обратную сторону, при вызове РеквизитФормыВЗначение, в создаваемом объекте реквизиты хранилища значений инициализируются пустыми, что приводит к безвозвратной потере ранее записанных двоичных данных в базе данных при стандартной записи.

Способ 1. Использование добавленных реквизитов формы и временного хранилища

Наиболее универсальный и чистый подход — не пытаться синхронизировать тяжелое хранилище значений через стандартный реквизит Объект формы, а организовать передачу через адреса временного хранилища или вспомогательные реквизиты строк табличной части.

Разберем пошаговый алгоритм реализации:

  1. В табличную часть формы добавляем реквизит АдресХранилища (тип Строка) или реквизит с типом Произвольный.
  2. В обработчике ПриЧтенииСозданииНаСервере или ПриСозданииНаСервере считываем объект из базы данных, извлекаем данные из каждой строки и помещаем их во временное хранилище с привязкой к уникальному идентификатору формы.
  3. Пользователь открывает отдельную форму редактирования/просмотра, куда передается только адрес конкретной строки.
  4. После редактирования обновленные данные помещаются обратно во временное хранилище по тому же адресу.
  5. В обработчике ПередЗаписьюНаСервере считываем данные из временного хранилища и заполняем табличную часть реального объекта через параметр ТекущийОбъект.

Рассмотрим пример кода чтения данных при открытии формы:


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

Способ 2. Сохранение данных через параметр ТекущийОбъект

Выясним, как правильно сохранить отредактированные двоичные данные в базу. Использование метода РеквизитФормыВЗначение("Объект") для всей формы с последующей записью приведет к сбросу хранилищ значений в пустые. Чтобы избежать ручных манипуляций и ошибок, необходимо использовать событие формы ПередЗаписьюНаСервере, в котором платформа предоставляет параметр ТекущийОбъект.

Параметр ТекущийОбъект содержит реальный экземпляр прикладного объекта, готовый к физической записи в СУБД. Посмотрим, как выглядит обработка сохранения:


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

Способ 3. Организация редактирования через отдельную форму и оповещения

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

Разберем по шагам, как настроить интерактивное взаимодействие пользователя с конкретной строкой:

  1. В событии таблицы формы Выбор или в обработчике команды кнопки получаем текущую строку через Элементы.ТабличнаяЧасть.ТекущиеДанные.
  2. Передаем адрес временного хранилища или уникальный ключ строки в параметрах открытия формы-редактора.
  3. В форме редактирования получаем данные, даем пользователю внести правки, запаковываем результат обратно во временное хранилище и вызываем ОповеститьОВыборе() или Оповестить().
  4. В исходной форме перехватываем оповещение и устанавливаем признак модифицированности формы Модифицированность = Истина;.

Пример вызова окна редактирования на клиенте:


&НаКлиенте
Процедура ТабличнаяЧастьВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    ТекущиеДанные = Элементы.ТабличнаяЧасть.ТекущиеДанные;
    
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("АдресДанных", ТекущиеДанные.АдресХранилища);
    
    ОповещениеОЗакрытии = Новый ОписаниеОповещения("ПослеРедактированияХранилища", ЭтотОбъект, ТекущиеДанные.НомерСтроки);
    ОткрытьФорму("Обработка.РедакторДанных.Форма.Форма", ПараметрыФормы, ЭтотОбъект,,,, ОповещениеОЗакрытии, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеРедактированияХранилища(Результат, ДополнительныеПараметры) Экспорт
    
    Если Результат = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Модифицированность = Истина;
    
КонецПроцедуры

Важные рекомендации по оптимизации и стабильности

При проектировании механизмов работы с хранилищами значений в коллекциях необходимо учитывать следующие технические нюансы:

  1. Очистка памяти: Всегда передавайте УникальныйИдентификатор формы вторым параметром в метод ПоместитьВоВременноеХранилище. Это предотвратит утечки оперативной памяти на сервере приложений 1С, так как временные данные будут автоматически уничтожены при закрытии формы сеансом пользователя.
  2. Суррогатные ключи: Если в табличной части формы пользователь может свободно менять порядок строк (перемещать вверх/вниз) или удалять строки, сопоставление по числовым индексам может дать сбой. Для надежной связки рекомендуется добавить в табличную часть реквизит КлючСтроки (тип Строка, содержащий строковое представление Новый УникальныйИдентификатор()). Это гарантирует точное сопоставление бинарных данных со строкой объекта при любых интерактивных манипуляциях с таблицей.
  3. Ленивая загрузка (On-demand): Не загружайте содержимое всех хранилищ значений сразу при открытии формы, если строк в таблице много. Достаточно выводить текстовое представление (например, размер файла или признак наличия), а считывание данных из ХранилищеЗначения выполнять только в момент непосредственного запроса пользователем.
← На главную