Как получить значение из программно добавленной колонки в СправочникСписок

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

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

Проанализируем причины такого поведения платформы 1С и разберем проверенные способы решения этой задачи.

Почему значение недоступно в источнике данных

Для понимания проблемы разберем внутреннюю архитектуру работы списков в платформе 1С:

  1. Разделение данных и интерфейса: коллекция ЭлементыФормы.ИмяТаблицы.Колонки управляет исключительно визуальным отображением элемента ТабличноеПоле. Добавление колонки в эту коллекцию не добавляет реквизит в сам объект данных.
  2. Неизменяемость структуры динамического списка: объект СправочникСписок.<Имя> формируется платформой динамически на основе метаданных конфигурации. В режиме исполнения в него нельзя добавить новое поле для хранения произвольных значений.
  3. Время жизни оформления строки: объект ОформлениеСтроки (в обработчике ПриВыводеСтроки) существует исключительно в момент отрисовки видимых строк на экране. Как только строка отрисована, платформа уничтожает этот объект. Записанные в ОформлениеСтроки.Ячейки.<ИмяКолонки>.Значение данные никуда не сохраняются и не попадают в коллекцию ТекущиеДанные.

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

Способ 1. Хранение рассчитанных данных в кэше формы (Соответствие)

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

Разберем по шагам реализацию данного подхода:

  1. Объявляем переменную кэша в модуле формы.
  2. Оптимизируем расчет: вместо построчного вычисления в ПриВыводеСтроки используем событие ПриПолученииДанных, которое обрабатывает массив строк пакетом за один запрос.
  3. Заполняем кэш и оформление ячеек.
  4. При необходимости прочитать данные по текущей строке обращаемся к переменной кэша по ссылке.

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


Перем КэшПланаЗакупок;

Процедура ПриОткрытии()
    КэшПланаЗакупок = Новый Соответствие;
КонецПроцедуры

Процедура НоменклатураПланЗакупокПриПолученииДанных(Элемент, ОформленияСтрок)
    
    // Собираем массив ссылок только для видимых строк, для которых еще нет данных в кэше
    МассивСсылок = Новый Массив;
    Для Каждого Оформление Из ОформленияСтрок Цикл
        ТекСсылка = Оформление.ДанныеСтроки.Ссылка;
        Если КэшПланаЗакупок[ТекСсылка] = Неопределено Тогда
            МассивСсылок.Добавить(ТекСсылка);
        КонецЕсли;
    КонецЦикла;
    
    // Если есть нерассчитанные строки, выполняем расчет пакетом
    Если МассивСсылок.Количество() > 0 Тогда
        // Здесь выполняется один запрос на расчет остатков/планов для МассивСсылок
        // Для примера заполним кэш
        Для Каждого ТекСсылка Из МассивСсылок Цикл
            РассчитанноеКво = 100; // Результат вычислений
            КэшПланаЗакупок.Вставить(ТекСсылка, РассчитанноеКво);
        КонецЦикла;
    КонецЕсли;
    
    // Устанавливаем значения в ячейки из кэша
    Для Каждого Оформление Из ОформленияСтрок Цикл
        ТекСсылка = Оформление.ДанныеСтроки.Ссылка;
        Оформление.Ячейки.ПланЗакупкиКво.Значение = КэшПланаЗакупок[ТекСсылка];
    КонецЦикла;

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

Теперь, когда нам потребуется получить значение колонки для текущей или найденной строки в произвольной процедуре формы, мы обращаемся напрямую к нашему кэшу:


Процедура ОбработатьВыбраннуюСтроку()
    
    СтрокаДанных = ЭлементыФормы.НоменклатураПланЗакупок.ТекущиеДанные;
    Если СтрокаДанных = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Получаем значение из кэша по ссылке
    ЗначениеПлана = КэшПланаЗакупок[СтрокаДанных.Ссылка];
    
    Если ЗначениеПлана = Неопределено Тогда
        // Если строка еще не отрисовывалась и не попала в кэш, рассчитываем по требованию
        ЗначениеПлана = РассчитатьПланДляЭлемента(СтрокаДанных.Ссылка);
        КэшПланаЗакупок.Вставить(СтрокаДанных.Ссылка, ЗначениеПлана);
    КонецЕсли;
    
    Сообщить("План закупки: " + ЗначениеПлана);

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

Способ 2. Вычисление значения функции по требованию

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

Посмотрим, как выглядит такой вызов:


Функция РассчитатьПланЗакупки(ТекСсылка)
    
    Остаток = УправлениеФронтомКассира.ПолучитьОстатокТовараПланЗакупок(БазСклад, ТекСсылка, ДатаРасчетов);
    МинОстаток = ТекСсылка.МинимальныйОстаток;
    
    Возврат Макс(0, МинОстаток - Остаток);

КонецФункции

Процедура КнопкаВыполнитьНажатие(Кнопка)
    
    ТекДанные = ЭлементыФормы.НоменклатураПланЗакупок.ТекущиеДанные;
    Если ТекДанные <> Неопределено Тогда
        КоличествоПлана = РассчитатьПланЗакупки(ТекДанные.Ссылка);
        // Используем полученное значение в дальнейших алгоритмах
    КонецЕсли;

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

Способ 3. Переход на использование Таблицы Значений

Если разрабатываемая форма представляет собой рабочее место (АРМ), в котором пользователь должен сортировать список по вычисляемым колонкам, выполнять поиск или массово редактировать расчетные показатели, использование СправочникСписок становится неэффективным.

В такой ситуации оптимальным решением является смена типа источника данных:

  1. Создаем реквизит формы с типом ТаблицаЗначений.
  2. Назначаем эту таблицу источником данных для элемента ТабличноеПоле.
  3. Программно добавляем нужные колонки в саму таблицу значений через метод Таблица.Колонки.Добавить(...).
  4. Заполняем таблицу одним запросом при открытии формы или по нажатию кнопки «Обновить».

В этом случае к расчетным колонкам можно обращаться стандартным образом через ЭлементыФормы.НоменклатураПланЗакупок.ТекущиеДанные.ПланЗакупкиКво, так как колонка физически существует в структуре источника данных.

← На главную