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

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

При разработке интерфейсов на Обычных формах (ОФ) программисты часто сталкиваются с ситуацией, когда в табличную часть документа или обработки необходимо вывести данные, которых нет в физической структуре объекта. Например, в таблице хранится только ссылка на номенклатуру, но пользователю нужно видеть её артикул, остаток на складе или страну происхождения. Рассмотрим, как правильно реализовать заполнение таких «виртуальных» колонок, не перегружая систему лишними запросами к базе данных.

Постановка задачи и анализ ситуации

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

Выбор правильного события: ПриВыводеСтроки против ПриПолученииДанных

Для решения задачи новички часто используют событие ПриВыводеСтроки. Проанализируем, почему это не лучший путь. Данное событие срабатывает каждый раз, когда строка отрисовывается на экране. Если мы напишем код типа:

ОформлениеСтроки.Ячейки.Артикул.УстановитьТекст(ОформлениеСтроки.ДанныеСтроки.Номенклатура.Артикул);

Система будет выполнять обращение «через точку». В мире 1С это означает отдельный SQL-запрос к базе данных для каждой строки при каждом движении мышки или прокрутке списка. Если в таблице 100 строк, интерфейс начнет заметно «тормозить». Поэтому мы рекомендуем использовать событие ПриПолученииДанных.

Реализация через событие ПриПолученииДанных

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

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

Пример программного кода для реализации этого метода:


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

    Если СоответствиеСсылок.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;

    // 2. Формируем массив для запроса
    МассивСсылок = Новый Массив;
    Для Каждого КлючИЗначение Из СоответствиеСсылок Цикл
        МассивСсылок.Добавить(КлючИЗначение.Ключ);
    КонецЦикла;

    // 3. Выполняем один запрос ко всем нужным данным
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.Ссылка КАК Ссылка,
    |   Номенклатура.Артикул КАК Артикул,
    |   Номенклатура.Производитель.Наименование КАК Производитель
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   Номенклатура.Ссылка В(&МассивСсылок)";
    
    Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
    Выборка = Запрос.Выполнить().Выбрать();

    // Заполняем соответствие результатами запроса
    Пока Выборка.Следующий() Цикл
        СтруктураДанных = Новый Структура("Артикул, Производитель");
        ЗаполнитьЗначенияСвойств(СтруктураДанных, Выборка);
        СоответствиеСсылок.Вставить(Выборка.Ссылка, СтруктураДанных);
    КонецЦикла;

    // 4. Отрисовываем данные в ячейках
    Для Каждого Оформление Из ОформленияСтрок Цикл
        Если Оформление.ДанныеСтроки <> Неопределено Тогда
            Данные = СоответствиеСсылок[Оформление.ДанныеСтроки.Номенклатура];
            Если Данные <> Неопределено Тогда
                Оформление.Ячейки.Артикул.УстановитьТекст(Данные.Артикул);
                Оформление.Ячейки.Производитель.УстановитьТекст(Данные.Производитель);
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;

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

Оптимизация с использованием кэширования

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

Для этого объявим переменную КэшДанныхНоменклатуры в самом верху модуля формы. При получении данных сначала будем проверять, нет ли ссылки в кэше, и запрашивать из базы только те объекты, которых там еще нет. Рассмотрим фрагмент кода:


Перем КэшДанныхНоменклатуры; // Объявляется в начале модуля

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

// В обработчике ПриПолученииДанных
// ... (Логика сбора ссылок, которых нет в КэшДанныхНоменклатуры) ...
// ... (Запрос и наполнение кэша новыми данными) ...
// В цикле отрисовки:
Данные = КэшДанныхНоменклатуры[Оформление.ДанныеСтроки.Номенклатура];

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

Проблема редактирования виртуальных колонок

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

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

Дополнительные возможности оформления

Использование ОформлениеСтроки позволяет не только выводить текст, но и динамически менять визуальное состояние ячеек. Например, если артикул не заполнен, мы можем подсветить ячейку красным цветом:


Если ПустаяСтрока(Данные.Артикул) Тогда
    Оформление.Ячейки.Артикул.ЦветФона = WebЦвета.СветлоРозовый;
КонецЕсли;

Такой гибкости в Обычных формах можно добиться только через программный код в указанных событиях, в отличие от Управляемых форм, где применяется механизм «Условного оформления». При необходимости можно воспользоваться конструктором кода условного оформления табличных частей.

Резюме

Подведем итоги. Для программного заполнения строк табличной части на обычных формах данными из связанных объектов:

Использование этого подхода сделает ваши формы быстрыми, а интерфейс — информативным для пользователя.

← На главную