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

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

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

В этой статье мы подробно разберем, как правильно реализовать вычисляемую колонку на управляемой форме 1С 8.3, как оптимизировать расчет данных для обеспечения высокой производительности интерфейса, а также рассмотрим варианты программного создания таких колонок. Для упрощения этой задачи и добавления элементов на управляемые формы без написания кода можно использовать инструмент для интерактивного добавления реквизитов на форму.

Способ 1. Добавление колонки через реквизиты формы в конфигураторе

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

  1. Откроем редактор управляемой формы нужного документа или справочника.
  2. В правой верхней части редактора перейдем на вкладку Реквизиты.
  3. Развернем дерево основного реквизита формы (обычно это Объект) и найдем нужную табличную часть (например, Товары).
  4. Нажмем правой кнопкой мыши по имени табличной части и выберем пункт меню Добавить колонку реквизита.
  5. Зададим имя нового реквизита (например, ОстатокТовара) и укажем его тип данных (например, Число).
  6. Теперь перетащим созданный реквизит из правой панели в левую — в дерево элементов формы, внутрь нашей таблицы. Платформа автоматически создаст элемент формы (поле) и свяжет его через свойство ПутьКДанным (которое примет вид Объект.Товары.ОстатокТовара).

Таким образом, мы получили полноценную колонку в табличной части на форме, которая физически не существует в табличной части объекта в базе данных.

Способ 2. Заполнение и расчет данных на сервере

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

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


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    
    // Вызываем процедуру расчета и заполнения вычисляемой колонки
    ЗаполнитьВычисляемыеДанныеНаСервере();
    
КонецПроцедуры

Способ 3. Оптимальный алгоритм расчета (пакетное заполнение)

Крайне важно избегать типичной ошибки: выполнения запросов к базе данных в цикле для каждой строки табличной части. Если в таблице будет 100-200 строк, форма будет открываться очень долго из-за сотен мелких запросов к СУБД. Нам необходимо применить пакетный метод получения данных.

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

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

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


&НаСервере
Процедура ЗаполнитьВычисляемыеДанныеНаСервере()
    
    // Шаг 1. Собираем массив уникальных ссылок на Номенклатуру
    МассивНоменклатуры = Новый Массив;
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        Если ЗначениеЗаполнено(СтрокаТЧ.Номенклатура) Тогда
            // Избегаем дублирования в массиве параметров
            Если МассивНоменклатуры.Найти(СтрокаТЧ.Номенклатура) = Неопределено Тогда
                МассивНоменклатуры.Добавить(СтрокаТЧ.Номенклатура);
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    Если МассивНоменклатуры.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Шаг 2. Выполняем один запрос к базе данных (получаем свободные остатки)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
        |	ТоварыНаСкладахОстатки.ВНаличииОстаток КАК Остаток
        |ИЗ
        |	РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура В (&МассивНоменклатуры)) КАК ТоварыНаСкладахОстатки";
    
    Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
    РезультатЗапроса = Запрос.Выполнить();
    
    // Шаг 3. Заполняем Соответствие для быстрой выборки в памяти
    СоответствиеОстатков = Новый Соответствие;
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        СоответствиеОстатков.Вставить(Выборка.Номенклатура, Выборка.Остаток);
    КонецЦикла;
    
    // Шаг 4. Обходим строки табличной части и заполняем форму
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        Остаток = СоответствиеОстатков.Получить(СтрокаТЧ.Номенклатура);
        СтрокаТЧ.ОстатокТовара = ?(Остаток = Неопределено, 0, Остаток);
    КонецЦикла;
    
КонецПроцедуры

Способ 4. Динамический расчет при изменении данных пользователем

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

Рассмотрим, как настроить интерактивный пересчет:

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

Посмотрим на пример кода обработчика события:


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

&НаСервереБезКонтекста
Функция ПолучитьОстатокНоменклатурыНаСервере(ВыбраннаяНоменклатура)
    
    Если Не ЗначениеЗаполнено(ВыбраннаяНоменклатура) Тогда
        Возврат 0;
    КонецЕсли;
    
    // Запрос для получения остатка по одной позиции номенклатуры
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	ЕСТЬNULL(ТоварыНаСкладахОстатки.ВНаличииОстаток, 0) КАК Остаток
        |ИЗ
        |	РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура = &Номенклатура) КАК ТоварыНаСкладахОстатки";
        
    Запрос.УстановитьПараметр("Номенклатура", ВыбраннаяНоменклатура);
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Остаток;
    КонецЕсли;
    
    Возврат 0;
    
КонецФункции

Способ 5. Программное добавление вычисляемой колонки

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

Проанализируем пример программного добавления колонки в процедуре ПриСозданииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Шаг 1. Создаем и добавляем новый реквизит в структуру формы
    МассивРеквизитов = Новый Массив;
    
    // Параметры конструктора РеквизитФормы: Имя, Тип, Путь, Заголовок, СохраняемыеДанные
    ТипРеквизита = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 0));
    НовыйРеквизит = Новый РеквизитФормы("СвободныйРезерв", ТипРеквизита, "Объект.Товары", "Резерв", Истина);
    МассивРеквизитов.Добавить(НовыйРеквизит);
    
    // Применяем изменения структуры реквизитов формы
    ИзменитьРеквизиты(МассивРеквизитов);
    
    // Шаг 2. Создаем визуальный элемент на форме для отображения данных
    ТаблицаФормы = Элементы.Товары;
    НовоеПоле = Элементы.Добавить("ТоварыСвободныйРезерв", Тип("ПолеФормы"), ТаблицаФормы);
    
    НовоеПоле.Вид = ВидПоляФормы.ПолеВвода;
    НовоеПоле.ПутьКДанным = "Объект.Товары.СвободныйРезерв";
    НовоеПоле.Заголовок = "Свободный резерв";
    НовоеПоле.ТолькоПросмотр = Истина; // Защищаем расчетную колонку от ручного редактирования
    
КонецПроцедуры

Способ 6. Вывод свойств связанных объектов через интерфейс без кода

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

Для этого выполним следующие действия прямо в режиме предприятия:

  1. В верхнем меню табличной части нажмем кнопку Ещё и выберем команду Изменить форму.
  2. В открывшемся дереве элементов найдем и выделим поле Номенклатура (или другое ссылочное поле ТЧ).
  3. Нажмем на кнопку Добавить поля на панели инструментов окна настройки формы.
  4. В появившемся списке свойств номенклатуры отметим галочкой нужные поля (например, Артикул) и нажмем кнопку ОК.

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

← На главную