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

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

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

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

Почему добавленной колонки нет в ТекущиеДанные

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

  1. Источник данных (модель): содержит физические реквизиты объекта и ссылки из базы данных. Свойство ТекущиеДанные возвращает строку именно источника данных. Если реквизита нет в метаданных справочника, в ТекущиеДанные он не появится.
  2. Слой отображения (представление): управляется событиями ПриВыводеСтроки и ПриПолученииДанных. Заполняя ОформлениеСтрок, разработчик меняет только визуальный текст ячеек на экране, но не сохраняет эти данные в строке источника.

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

Решение 1. Кэширование данных на уровне формы

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

  1. В модуле формы объявляем переменную с типом Соответствие для хранения рассчитанных данных.
  2. В событии ПриПолученииДанных рассчитываем показатели сразу для всей пачки выводимых строк (чтобы избежать лишних запросов к СУБД) и сохраняем их в кэш, где ключом будет ссылка на элемент справочника.
  3. В процедуре ПриАктивизацииСтроки извлекаем данные из кэша по ссылке текущей строки.

Посмотрим на пример программной реализации:


Перем мКэшДанных;

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

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

Процедура СправочникСписокПриАктивизацииСтроки(Элемент)
    СтрокаДанных = Элемент.ТекущиеДанные;
    Если СтрокаДанных = Неопределено Или СтрокаДанных.ЭтоГруппа Тогда
        Возврат;
    КонецЕсли;
    
    // Получаем значение из кэша по ссылке
    ТекущееКоличество = мКэшДанных[СтрокаДанных.Ссылка];
    
    // Если по какой-то причине строка не успела кэшироваться, выполняем точечный расчет
    Если ТекущееКоличество = Неопределено Тогда
        ТекущееКоличество = ПолучитьКоличествоПоНоменклатуре(СтрокаДанных.Ссылка);
        мКэшДанных.Вставить(СтрокаДанных.Ссылка, ТекущееКоличество);
    КонецЕсли;
КонецПроцедуры

Решение 2. Расчет только для текущей активной строки

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

  1. В процедуре ПриАктивизацииСтроки считываем ссылку текущей строки.
  2. Выполняем запрос остатка или цены для выбранной позиции.
  3. Отображаем результат в отдельном элементе управления на форме (например, в поле надписи).

Такой подход существенно снижает нагрузку на базу данных при быстрой прокрутке объемного списка.

Решение 3. Использование Таблицы или Дерева значений

Рассмотрим вариант с полной заменой типа источника данных. Если необходимо производить сортировки и отборы по вычисляемым колонкам прямо в списке, используют ТаблицаЗначений или ДеревоЗначений:

  1. ДеревоЗначений: позволяет сохранить визуальную иерархию папок и элементов. Формируется запросом с конструкцией ИТОГИ ПО Иерархия с левым соединением к регистрам остатков и цен.
  2. ТаблицаЗначений: подходит для плоских списков или списков с ручной навигацией по группам через отбор по родителю.

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

Особенности в управляемых формах

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

← На главную