При разработке функционала на платформе 1С:Предприятие 8.3 в управляемых формах часто возникает задача отображения в табличной части документа дополнительной информации, которая не хранится в базе данных, а является результатом вычислений. Это так называемые "расчетные" или "виртуальные" колонки. Мы хотим добавить такую колонку программно, чтобы она появлялась только на форме, не требуя изменения структуры объекта конфигурации (документа).
Наша цель – создать новую колонку в табличной части документа, например, "Товары", которая будет содержать расчетное значение, такое как "ЦенаСУчетомСкидки". Эта колонка должна быть добавлена динамически во время выполнения программы, без изменения конфигурации базы данных. Она будет отображаться на форме документа и может быть использована для визуализации данных пользователю, но её содержимое не будет сохраняться в базе при записи документа.
Наш первоначальный подход, заключающийся в прямом добавлении колонки через
Элементы.Товары.ПодчиненныеЭлементы.Вставить()
Элементы.Товары.Колонки.Вставить()
Для успешного программного добавления расчетной колонки в табличную часть управляемой формы мы пройдем через несколько этапов. Рассмотрим каждый шаг подробно (кстати, существуют способы добавления реквизитов и элементов без кодирования).
Первым делом нам необходимо создать новый реквизит формы, который будет выступать в роли хранилища данных для нашей расчетной колонки. Важно понимать, что это будет реквизит именно формы, а не реквизит объекта информационной базы. Он будет существовать только в контексте открытой формы.
Для создания реквизита формы мы используем конструктор объекта РеквизитФормы. При этом критически важно правильно указать его параметры:
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15,2)) для числа с двумя знаками после запятой).
Объект.Товары
"Объект.Товары". Распространенной ошибкой является указание здесь элемента формы, например, Элементы.Товары, что приведет к ошибке "Недопустимый путь к реквизиту".Пример создания реквизита формы:
МассивРеквизитов = Новый Массив;
МассивРеквизитов.Добавить(Новый РеквизитФормы("ЦенаСУчетомСкидок", Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(15,2)), "Объект.Товары", "Цена скид.", Ложь));
Здесь мы создаем реквизит "ЦенаСУчетомСкидок" с типом Число, владельцем "Объект.Товары" (что указывает на табличную часть объекта формы) и заголовком "Цена скид.". Обратите внимание, что мы добавляем его в массив, так как метод ИзменитьРеквизиты принимает массив.
После того как мы создали объект РеквизитФормы, форма еще не знает о его существовании. Для того чтобы форма "приняла" новый реквизит и он стал доступен для использования, нам необходимо вызвать метод ЭтаФорма.ИзменитьРеквизиты(). Этот метод принимает массив объектов РеквизитФормы, которые мы хотим добавить, изменить или удалить.
Это критически важный шаг, без которого добавленный реквизит не будет виден для формы, и последующие попытки привязать к нему элемент формы приведут к ошибке.
Пример применения изменений:
ЭтаФорма.ИзменитьРеквизиты(МассивРеквизитов);
Вызов этой процедуры сообщает платформе, что структура данных формы изменилась, и теперь она включает наш новый реквизит "ЦенаСУчетомСкидок" как часть табличной части "Объект.Товары".
После того как реквизит формы успешно добавлен, нам нужен визуальный элемент на форме, который будет отображать его содержимое. Для этого мы создадим элемент формы типа ПолеФормы и разместим его внутри элемента табличной части. Чтобы упростить программное изменение форм, можно использовать метод Элементы.Добавить() или Элементы.Вставить().
Элементы.Добавить(Имя, Тип, Родитель): Добавляет элемент в конец коллекции подчиненных элементов родителя.Элементы.Вставить(Имя, Тип, Родитель, ПередЭлементом): Вставляет элемент перед указанным существующим элементом. Это полезно, когда мы хотим поместить новую колонку в определенное место, а не просто в конец табличной части.Пример создания элемента формы:
Эл = Элементы.Вставить("КолонкаЦенаСУчетомСкидок", Тип("ПолеФормы"), Элементы.Товары, Элементы.ТоварыПроцентАвтоматическойСкидки);
Здесь мы вставляем новый элемент с именем "КолонкаЦенаСУчетомСкидок" (важно, чтобы имя элемента формы не совпадало с именем реквизита формы, хотя платформа обычно их различает по контексту) типа ПолеФормы в табличную часть Элементы.Товары перед колонкой "ПроцентАвтоматическойСкидки".
Этот шаг является ключевым для связи визуального элемента с нашим только что созданным реквизитом формы. Мы делаем это, присваивая свойству ПутьКДанным нашего нового элемента формы строковое представление полного пути к реквизиту формы.
Путь должен быть составлен таким образом, чтобы он указывал на наш динамически созданный реквизит внутри табличной части, например, "Объект.Товары.ЦенаСУчетомСкидок". Ошибки здесь могут быть связаны с неверным синтаксисом пути или попыткой привязаться к реквизиту, который не был успешно добавлен через ИзменитьРеквизиты().
Пример привязки к данным:
Эл.ПутьКДанным = "Объект.Товары.ЦенаСУчетомСкидок";
После этой операции элемент формы "КолонкаЦенаСУчетомСкидок" будет отображать значения, хранящиеся в реквизите "ЦенаСУчетомСкидок" каждой строки табличной части "Объект.Товары".
Для того чтобы наша новая колонка выглядела и вела себя корректно, нам нужно настроить её свойства. Для расчетных колонок часто бывает полезно установить свойство ТолькоПросмотр = Истина, чтобы пользователь не мог вручную изменять расчетные значения. Также мы можем указать Вид поля (например, ВидПоляФормы.ПолеВвода) и другие параметры, такие как Заголовок, Ширина и т.д.
Пример настройки свойств:
Эл.Вид = ВидПоляФормы.ПолеВвода;
Эл.ТолькоПросмотр = Истина; // Для расчетной колонки часто это необходимо
Таким образом, мы настраиваем внешний вид и поведение колонки, делая её удобной для восприятия пользователем (при необходимости сложного оформления может потребоваться декомпиляция условного оформления).
Соберем все шаги вместе в одном блоке кода. Этот код обычно размещается в обработчике события формы ПриСозданииНаСервере, чтобы колонка создавалась при открытии формы.
// 1. Создание реквизита формы
МассивРеквизитов = Новый Массив;
РеквизитДляКолонки = Новый РеквизитФормы(
"ЦенаСУчетомСкидок",
Новый ОписаниеТипов("Число",Новый КвалификаторыЧисла(15,2)),
"Объект.Товары", // Важно: путь к данным, а не элемент формы
"Цена скид.",
Ложь // Недоступно для пользователя в настройках формы
);
МассивРеквизитов.Добавить(РеквизитДляКолонки);
// 2. Применение изменений реквизитов формы
ЭтаФорма.ИзменитьРеквизиты(МассивРеквизитов);
// 3. Создание элемента формы для отображения
// Вставляем новую колонку перед существующей колонкой "ПроцентАвтоматическойСкидки"
ЭлКолонка = Элементы.Вставить("ЦенаСУчетомСкидок_Элемент", Тип("ПолеФормы"), Элементы.Товары, Элементы.ТоварыПроцентАвтоматическойСкидки);
// 4. Привязка элемента формы к данным
ЭлКолонка.ПутьКДанным = "Объект.Товары.ЦенаСУчетомСкидок"; // Важно: полный путь к динамическому реквизиту
// 5. Настройка свойств элемента формы
ЭлКолонка.Вид = ВидПоляФормы.ПолеВвода;
ЭлКолонка.ТолькоПросмотр = Истина; // Расчетная колонка обычно только для просмотра
ЭлКолонка.Заголовок = РеквизитДляКолонки.Заголовок; // Используем заголовок из реквизита
После того как колонка программно добавлена на форму, нам необходимо обеспечить её заполнение расчетными данными. Это обычно делается в обработчиках событий, когда данные табличной части изменяются или загружаются. Разберем, в каких событиях формы мы можем производить расчеты:
ПриЧтенииНаСервере: Этот обработчик срабатывает при первой загрузке данных объекта на форму. Здесь мы можем выполнить первоначальный расчет для всех строк табличной части.
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
Для Каждого СтрокаТЧ Из ТекущийОбъект.Товары Цикл
// Здесь СтрокаТЧ - это строка объекта информационной базы
// Мы не можем напрямую изменить реквизит формы через СтрокаТЧ
// Вместо этого мы ищем соответствующую строку в данных формы.
// Допустим, у нас есть уникальный идентификатор строки или индекс
// Для простоты, если реквизит уже добавлен, можно попробовать так:
СоответствующаяСтрокаФормы = Элементы.Товары.ТекущиеДанные; // Это не сработает для всех строк
// Нужно найти строку по индексу или ключу
// Корректнее будет работать с данными формы напрямую:
Для Каждого СтрокаДанныхФормы Из Объект.Товары Цикл
// Выполняем расчет
СтрокаДанныхФормы.ЦенаСУчетомСкидок = СтрокаДанныхФормы.Цена * (1 - СтрокаДанныхФормы.ПроцентСкидки / 100);
КонецЦикла;
КонецЦикла;
// Или если ТЧ формы - это Объект.Товары
Для Каждого СтрокаТЧФормы Из Объект.Товары Цикл
СтрокаТЧФормы.ЦенаСУчетомСкидок = СтрокаТЧФормы.Цена * (1 - СтрокаТЧФормы.ПроцентСкидки / 100);
КонецЦикла;
КонецПроцедуры
ПриИзменении (для колонок табличной части): Если расчетная колонка зависит от значений других колонок табличной части, нам нужно пересчитывать её при изменении этих зависимых колонок. Мы можем создать обработчик события "ПриИзменении" для полей, от которых зависит расчет.
&НаКлиенте
Процедура ТоварыЦенаПриИзменении(Элемент)
РассчитатьЦенуСУчетомСкидкиТекущейСтроки();
КонецПроцедуры
&НаКлиенте
Процедура ТоварыПроцентСкидкиПриИзменении(Элемент)
РассчитатьЦенуСУчетомСкидкиТекущейСтроки();
КонецПроцедуры
&НаКлиенте
Процедура РассчитатьЦенуСУчетомСкидкиТекущейСтроки()
// Получаем текущую строку табличной части
ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
// Выполняем расчет
ТекущаяСтрока.ЦенаСУчетомСкидок = ТекущаяСтрока.Цена * (1 - ТекущаяСтрока.ПроцентСкидки / 100);
КонецЕсли;
КонецПроцедуры
ПриСозданииНаСервере: Если расчеты просты и не зависят от данных, загружаемых при чтении, можно выполнить их здесь. Однако чаще здесь только добавляются реквизиты и элементы, а расчеты выносятся в ПриЧтенииНаСервере или отдельные функции.ПриПолученииДанныхНаСервере: Если требуется пересчитывать колонку при каждом обновлении данных на форме (например, после интерактивных действий пользователя, которые не вызывают явное изменение данных в ТЧ, но могут влиять на расчеты).Важно помнить, что доступ к данным табличной части для их изменения осуществляется через свойство объекта формы (например, Объект.Товары), а не через коллекцию элементов формы (Элементы.Товары). Изменение данных в Объект.Товары автоматически обновит отображение в связанном элементе формы.
При работе с программно добавляемыми расчетными колонками следует учитывать несколько важных моментов:
ПриСозданииНаСервере или в отдельной процедуре, вызываемой из него. Это гарантирует, что колонка будет создана при каждом открытии формы.
Использование реквизитов формы для создания расчетных колонок является стандартным и наиболее гибким подходом в управляемых формах 1С, когда нам необходимо отобразить данные, которые не хранятся в базе, но требуют вычисления на клиенте или сервере. Следуя этим шагам и учитывая нюансы, мы сможем успешно реализовать функционал динамических расчетных колонок в наших приложениях на 1С:Предприятие.