Как динамически добавлять реквизиты на форму в расширении 1С и обрабатывать их события, сохраняя обновляемость конфигурации

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

При доработке типовых конфигураций 1С (таких как ERP, КА, УТ), находящихся на поддержке, разработчики часто сталкиваются с дилеммой: заимствовать форму объекта в расширение или добавлять новые элементы программно. Заимствование тяжелой формы усложняет дальнейшие обновления конфигурации поставщика, так как форма «тянет» за собой множество связей. Программное добавление реквизитов лишено этого недостатка, но порождает другую сложность: как перехватить обработчик события (например, ПриИзменении) для нового элемента, не заимствуя саму форму в расширение?

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

---

Решение 1. Программный перехват события «ПриИзменении» без заимствования формы (через БСП)

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

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

Рассмотрим этот процесс пошагово:

Шаг 1. Программное создание реквизита и элемента формы

Внедрение кода по созданию реквизитов обычно выполняется в общем модуле МодификацияКонфигурацииПереопределяемый (в процедуре ПриСозданииНаСервере). Мы создаем реквизит, добавляем элемент на форму и привязываем событие ПриИзменении к предопределенной процедуре формы Подключаемый_ВыполнитьПереопределяемуюКоманду (или аналогичной, например, Подключаемый_ВыполнитьКоманду), которая гарантированно присутствует в модуле формы типового документа:


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

Шаг 2. Перехват события в общем модуле

Когда пользователь изменит значение в созданном поле, форма вызовет процедуру Подключаемый_ВыполнитьПереопределяемуюКоманду. Внутри этой процедуры происходит обращение к клиенскому переопределяемому модулю БСП.

Нам достаточно заимствовать в расширение общий модуль МодификацияКонфигурацииКлиентПереопределяемый и перехватить процедуру ВыполнитьПереопределяемуюКоманду с помощью аннотации &После или &Вместо:


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

В некоторых конфигурациях УТ/ERP также можно использовать механизм подписок на события БСП через вызов ОбщегоНазначенияУТ.УстановитьПодпискуНаСобытияИзмененияЭлементовФормы, который переназначает обработчик на Подключаемый_ПриИзменении_УстановитьДоступностьЭлементовПоСтатусуСервер, однако вышеописанный метод через ВыполнитьПереопределяемуюКоманду является наиболее универсальным для систем на БСП.

---

Решение 2. Разработка расширений, устойчивая к изменениям (метод «Ход конем»)

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

Суть проблемы стандартного заимствования:

Когда вы заимствуете форму (например, ФормаДокумента) из основной конфигурации в расширение, платформа автоматически копирует туда все связи этой формы с другими метаданными: типами реквизитов, справочниками, перечислениями. Если в очередном обновлении от фирмы «1С» изменится тип какого-то стороннего реквизита, который вы даже не трогали, ваше расширение перестанет применяться из-за несоответствия типов метаданных.

Пошаговый алгоритм метода «Ход конем» для изоляции формы:

  1. Создайте абсолютно пустую базу данных (файловую «пустышку») в том же режиме совместимости, что и ваша рабочая конфигурация.
  2. В этой пустой базе создайте объект с точно таким же именем, как у дорабатываемого объекта в рабочей базе (например, документ ЗаявкаНаРасходованиеДенежныхСредств) и добавьте ему форму с тем же именем.
  3. В модуле этой созданной пустой формы удалите все автоматически сгенерированные процедуры. В дереве элементов формы оставьте только те корневые группы, в которые вы планируете позиционировать свои новые элементы (например, ГруппаШапка или Страницы). Имена этих групп должны символ-в-символ совпадать с именами групп в оригинальной типовой конфигурации.
  4. Создайте в этой пустой базе расширение и заимствуйте туда эту «облегченную» форму.
  5. Добавьте в расширение на эту форму необходимые новые реквизиты и перетащите их интерактивно в нужные группы. Напишите необходимый код обработчиков в модуле формы расширения.
  6. Сохраните расширение в файл .cfe.
  7. Загрузите этот файл расширения в вашу рабочую базу ERP.

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

---

Глубокий анализ: как платформа 1С выполняет трехстороннее слияние управляемых форм (3-Way Merge)

Многие разработчики опасаются заимствовать формы в расширения, полагая, что при любом обновлении конфигурации поставщика им придется вручную переносить изменения в расширение. Однако платформа 1С обладает интеллектуальным механизмом автоматического объединения форм в режиме предприятия.

Этот процесс называется трехсторонним сравнением и слиянием. При инициализации формы платформа анализирует три ее состояния:

  1. Исходная форма (Ансестор) — состояние типовой формы на момент создания/заимствования в расширение.
  2. Измененная форма в расширении — форма с вашими доработками.
  3. Текущая форма в основной конфигурации — обновленная форма от поставщика после наката обновления.

Платформа сопоставляет изменения по следующим правилам:

Важное исключение: правило наибольшего ограничения для Булевых свойств

Особое внимание следует уделить свойствам булевого типа, отвечающим за доступность интерфейса: Видимость, Доступность, ТолькоПросмотр.

Для этих свойств стандартный алгоритм трехстороннего слияния работает по принципу наибольшего ограничения (логическое «И»). Рассмотрим практический сценарий, часто вызывающий вопросы у разработчиков:

Состояние / Источник Свойство «Видимость» Свойство «Доступность»
1. Исходная форма (на момент заимствования) Истина Истина
2. Изменения в расширении (вы не трогали свойства) Истина Истина
3. Обновление конфигурации от поставщика Ложь Ложь
Итог на экране пользователя Ложь (Элемент скрыт) Ложь (Элемент заблокирован)

В данном случае система видит, что в расширении свойство не менялось, а в обновлении оно изменилось на Ложь. Элемент скроется.

Однако, даже если вы в расширении принудительно установите Видимость = Истина, а конфигурация поставщика в обновлении установит Видимость = Ложь — платформа применит правило наибольшего ограничения, и элемент все равно будет скрыт в режиме предприятия.

Как обойти ограничение слияния свойств видимости?

Если вам критически важно гарантировать видимость или доступность элемента интерфейса вопреки изменениям в обновлении конфигурации, не полагайтесь на интерактивные свойства формы в расширении. Используйте программную установку свойств в обработчике ПриСозданииНаСервере (желательно с аннотацией &После):


&После("ПриСозданииНаСервере")
Процедура Расш1_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Принудительно включаем видимость элемента на клиенте, игнорируя настройки формы
    ЭтотОбъект.Элементы.ВажнаяКнопкаУправления.Видимость = Истина;
    ЭтотОбъект.Элементы.ВажнаяКнопкаУправления.Доступность = Истина;
    
    // Программная установка в кодовой части модуля всегда имеет наивысший приоритет
    // и выполняется после того, как платформа завершит динамическое слияние метаданных
    
    
КонецПроцедуры

---

Выводы и рекомендации для разработчиков

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

  1. Используйте программное создание элементов с маршрутизацией через переопределяемые модули БСП, если вам нужно добавить 1-2 простых реквизита ввода. Это обеспечит стопроцентную обновляемость базы без необходимости открывать конфигуратор расширения при релизах поставщика.
  2. Используйте метод «Ход конем» для изоляции заимствованных форм, если требуется сложная интерактивная верстка интерфейса на форме расширения и программирование объемной логики в ее модуле.
  3. Помните о правилах трехстороннего слияния: платформа корректно объединяет изменения интерфейса до тех пор, пока они не пересекаются на уровне конкретных свойств одних и тех же элементов. Для управления правами доступа, видимостью и доступностью всегда отдавайте приоритет программному коду в модулях форм, а не интерактивным галочкам в конфигураторе.
← На главную