Как вывести дополнительные сведения на управляемую форму элемента номенклатуры в 1С:УНФ?

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

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

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

Особенности архитектуры управляемых форм: почему нельзя просто создать поле

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

Элемент управляемой формы — это исключительно визуальное отображение. Поле формы типа ПолеФормы с видом ВидПоляФормы.ПолеВвода обязательно требует заполнения свойства ПутьКДанным. Попытка оставить ПутьКДанным пустым приводит к ошибке Недопустимое значение.

Для реализации динамического вывода полей необходимо соблюдать строгую двухзвенную последовательность:

  1. Программно создать и зарегистрировать реквизит формы с помощью метода ИзменитьРеквизиты().
  2. Создать визуальный элемент формы и связать его свойство ПутьКДанным с именем только что созданного реквизита.

Пошаговая реализация динамического вывода полей

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

В расширении создадим вспомогательный реквизит формы ТаблицаДополнительныхСведений типа ТаблицаЗначений с колонками Сведение (тип ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения) и Значение.

В обработчике ПриСозданииНаСервере получаем список сведений и их текущие значения для открытого объекта, динамически создаем реквизиты формы, а затем размещаем элементы интерфейса.

Посмотрим на пример программной инициализации реквизитов и элементов формы:


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

Организация сохранения данных: клиентская и серверная логика

Рассмотрим, как обрабатывать изменение значений в динамически созданных полях. При редактировании поля на клиенте вызывается единый подключаемый обработчик:


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

На сервере выполняется запись полученного значения в регистр сведений ДополнительныеСведения через НаборЗаписей:


&НаСервере
Процедура ЗаписатьСведенияНаСервере(ИндексТаблицы)
    
    // Проверяем, существует ли ссылка на объект в базе
    Если Не ЗначениеЗаполнено(Объект.Ссылка) Тогда
        Возврат;
    КонецЕсли;
    
    ТекущееСвойство = ТаблицаДополнительныхСведений.Получить(ИндексТаблицы).Сведение;
    НовоеЗначение = ЭтаФорма["РеквизитСведение_" + Строка(ИндексТаблицы)];
    
    НаборЗаписей = РегистрыСведений.ДополнительныеСведения.СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Объект.Установить(Объект.Ссылка);
    НаборЗаписей.Отбор.Свойство.Установить(ТекущееСвойство);
    
    // Если пользователь очистил поле ввода, очищаем запись в регистре
    Если ЗначениеЗаполнено(НовоеЗначение) Тогда
        Запись = НаборЗаписей.Добавить();    
        Запись.Объект = Объект.Ссылка;
        Запись.Свойство = ТекущееСвойство;
        Запись.Значение = НовоеЗначение;
    КонецЕсли;
    
    НаборЗаписей.Записать();
    
КонецПроцедуры

Важные архитектурные нюансы и ограничения

Проанализируем тонкости работы с платформой при реализации подобного механизма:

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