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

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

В чем заключается ошибка: элементы формы против данных формы

Рассмотрим типовую ситуацию. Разработчик программно создает реквизит через метод ИзменитьРеквизиты(), добавляет элемент управления ПолеФормы, привязывает его свойство ПутьКДанным к созданному реквизиту, а затем пытается присвоить значение напрямую найденному элементу интерфейса:


Эф = ЭтаФорма.Элементы.Найти("КоличествоКраски");
Эф = ПолучитьКоличество(Родитель);

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

Следующая частая ошибка — попытка обратиться к созданному реквизиту через основной реквизит формы Объект:


Объект[Эф.Имя] = ПолучитьКоличество(Родитель); // Вызовет ошибку: Поле объекта не обнаружено!

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

Корректный синтаксис обращения к динамическим реквизитам

Выясним причину путаницы с ключевыми словами ЭтотОбъект и ЭтаФорма. В контексте модуля управляемой формы ЭтотОбъект и ЭтаФорма указывают на саму форму как контейнер данных. Однако на клиенте в различных версиях платформы обращение через ЭтотОбъект может приводить к ошибке «Переменная не определена». Универсальным и надежным способом обращения к реквизитам формы на клиенте является использование ключевого слова ЭтаФорма.

Посмотрим на пример правильного присвоения значения реквизиту формы по имени:


// Обращение по строковому имени созданного реквизита:
ЭтаФорма[СтрЗаменить("Количество" + Родитель, " ", "")] = ПолучитьКоличество(Родитель);

// Либо с использованием имени найденного элемента, если они совпадают:
ЭтаФорма[Эф.Имя] = ПолучитьКоличество(Родитель);

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

Оптимизация клиент-серверного взаимодействия

Разберем процедуру обновления формы более детально. В исходном примере на каждое изменение строки таблицы выполнялось два раздельных серверных вызова: сначала для добавления реквизита и элемента, а затем — отдельная функция для расчета суммы. Множественные вызовы сервера приводят к заметным задержкам интерфейса. Оптимизируем код, объединив создание элементов и расчет значений в один серверный контекстный вызов.


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

&НаСервере
Процедура ОбновитьИтогиПоРодителюНаСервере(РодительНоменклатуры)
    Если Не ЗначениеЗаполнено(РодительНоменклатуры) Тогда
        Возврат;
    КонецЕсли;
    
    // Формируем уникальное корректное имя реквизита
    ИмяРеквизита = "Количество_" + СтрЗаменить(Строка(РодительНоменклатуры.УникальныйИдентификатор()), "-", "_");
    
    // Проверяем, существует ли уже элемент формы
    Элемент = Элементы.Найти(ИмяРеквизита);
    Если Элемент = Неопределено Тогда
        // 1. Создаем реквизит формы
        МассивРеквизитов = Новый Массив;
        МассивРеквизитов.Добавить(Новый РеквизитФормы(ИмяРеквизита, Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3))));
        ИзменитьРеквизиты(МассивРеквизитов);
        
        // 2. Создаем визуальный элемент формы
        Элемент = Элементы.Добавить(ИмяРеквизита, Тип("ПолеФормы"), Элементы.ГруппаКоличество);
        Элемент.Вид = ВидПоляФормы.ПолеНадписи;
        Элемент.ПутьКДанным = ИмяРеквизита;
        Элемент.Заголовок = "Итого " + СокращенSnapshot(Строка(РодительНоменклатуры));
    КонецЕсли;
    
    // 3. Рассчитываем сумму по всей табличной части
    СуммаКоличество = 0;
    Отбор = Новый Структура("Родитель", РодительНоменклатуры);
    НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);
    Для Каждого Стр Из НайденныеСтроки Цикл
        СуммаКоличество = СуммаКоличество + Стр.Количество;
    КонецЦикла;
    
    // 4. Присваиваем рассчитанное значение напрямую в контексте формы
    ЭтаФорма[ИмяРеквизита] = СуммаКоличество;
КонецПроцедуры

Архитектурные ограничения и потенциальные проблемы

При использовании программного создания элементов формы важно помнить о технических ограничениях платформы 1С:

  1. Тяжелый вызов метода ИзменитьРеквизиты(). Вызов перестроения реквизитов формы во время интерактивных действий пользователя (в обработчиках ПриИзменении) пересоздает модель формы на клиенте. Это может вызывать потерю фокуса активной строки, сброс текущей позиции редактирования и микрофризы интерфейса. Рекомендуется создавать структуру реквизитов заранее в процедуре ПриСозданииНаСервере.
  2. Правила именования идентификаторов. Конкатенация вида "Количество" + Родитель опасна: если наименование папки содержит кавычки, дефисы, пробелы или спецсимволы, платформа завершит работу аварийно из-за недопустимого имени переменной. Безопасно формировать имена на основе УникальныйИдентификатор() ссылки с заменой дефисов на подчеркивания.

Альтернативное решение: вывод через декорации без создания реквизитов

Если задача заключается только в визуальном информировании пользователя о суммах в подвале и введенные значения не требуется редактировать, создание реквизитов через ИзменитьРеквизиты() является избыточным. Гораздо эффективнее использовать элемент ДекорацияФормы с видом ВидДекорацииФормы.Надпись.

Рассмотрим преимущества этого подхода:

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

Посмотрим на пример реализации отображения итогов с помощью декораций:


&НаСервере
Процедура СоздатьДекорациюЕслиНужно(ИмяЭлемента, Заголовок)
    Декорация = Элементы.Найти(ИмяЭлемента);
    Если Декорация = Неопределено Тогда
        Декорация = Элементы.Добавить(ИмяЭлемента, Тип("ДекорацияФормы"), Элементы.ГруппаКоличество);
        Декорация.Вид = ВидДекорацииФормы.Надпись;
    КонецЕсли;
    Декорация.Заголовок = Заголовок;
КонецПроцедуры

Таким образом, для программного присвоения значений динамическим элементам необходимо обращаться к данным через коллекцию свойств формы ЭтаФорма[ИмяРеквизита], а для оптимизации интерфейса — отдавать предпочтение декорациям надписей, не перегружая форму динамическим добавлением реквизитов во время ввода данных.

← На главную