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

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

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

Метод 1: Использование типа данных ХранилищеЗначений

Это наиболее универсальный способ, который позволяет упаковать любой объект (включая СписокЗначений) в бинарные данные и сохранить его в базе данных. Проанализируем алгоритм реализации этого метода по шагам.

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

Во-вторых, на форме документа добавим колонку, связанную с этим реквизитом. Однако, так как ХранилищеЗначений не имеет стандартного редактора, нам потребуется программное вмешательство. Установим у элемента формы (поля ввода) свойство КнопкаВыбора = Истина и свойство РежимВыбораИзСписка = Ложь.

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


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

КонецПроцедуры

Метод 2: Визуализация данных через текстовую колонку

Проблема ХранилищаЗначений в том, что в ячейке таблицы пользователь будет видеть надпись "Хранилище значений" или пустоту. Это неудобно. Чтобы сделать интерфейс дружелюбным, применим технику «виртуальной колонки». Выясним, как это реализовать.

  1. Добавим на форму в таблицу колонку ПредставлениеДат с типом Строка. Эта колонка не должна быть связана с данными объекта (не ставим «Данные»).
  2. Используем событие таблицы ПриВыводеСтроки. В этом событии мы будем динамически формировать текст для отображения.

Посмотрим на пример реализации формирования текста:


Процедура ТоварыПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    
    // Пытаемся получить данные из бинарного реквизита
    Список = ДанныеСтроки.ДополнительныеДатыХранилище.Получить();
    
    Если ТипЗнч(Список) = Тип("СписокЗначений") И Список.Количество() > 0 Тогда
        Текст = "";
        Для Каждого ЭлементСписки Из Список Цикл
            Текст = Текст + Формат(ЭлементСписки.Значение, "ДФ=dd.MM.yyyy") + "; ";
        КонецЦикла;
        ОформлениеСтроки.Ячейки.ПредставлениеДат.УстановитьТекст(Текст);
    Иначе
        ОформлениеСтроки.Ячейки.ПредставлениеДат.УстановитьТекст("... нажмите для ввода ...");
    КонецЕсли;
    
КонецПроцедуры

Важный нюанс: Обработка ПриВыводеСтроки вызывается часто, поэтому внутри неё не рекомендуется выполнять тяжелые запросы. Но метод Получить() для небольших списков работает достаточно быстро.

Метод 3: Сериализация в строку (Альтернатива)

Если вам не нравится работать с бинарными данными, можно использовать строковый реквизит неограниченной длины. В 1С есть встроенные механизмы сериализации объектов в системную строку. Разберем, как использовать функции ЗначениеВСтрокуВнутр и ЗначениеИзСтрокиВнутр.

Этот способ удобен тем, что данные можно увидеть "глазами" в отладчике. Однако помните, что формат внутренней строки 1С специфичен и его не стоит пытаться парсить вручную. Работа с ним выглядит так:


// При сохранении:
ТекущаяСтрока.СтроковыйРеквизит = ЗначениеВСтрокуВнутр(СписокДат);

// При чтении:
СписокДат = ЗначениеИзСтрокиВнутр(ТекущаяСтрока.СтроковыйРеквизит);

Метод 4: Архитектурный подход с подчиненной табличной частью

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

Например, у нас есть ТЧ Товары и ТЧ ДатыПоставок. В ТЧ ДатыПоставок мы добавляем реквизит КлючСвязи (число), который соответствует индексу или уникальному идентификатору строки из ТЧ Товары. Преимущества такого подхода очевидны:

Вывод данных на печатную форму

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


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

Подведем итог: для реализации "списка в строке" на платформе 8.1 наиболее эффективным является использование ХранилищаЗначений в сочетании с программным вызовом метода ВыбратьЭлемент(). Это сохраняет чистоту структуры данных (не плодятся лишние таблицы) и обеспечивает интуитивно понятный интерфейс для пользователя.

← На главную