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

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

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

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

Решение 1. «Мягкое» заимствование формы (Рекомендуемый способ для платформы 8.3.14+)

Начиная с версии платформы 8.3.14, фирма «1С» кардинально переработала и оптимизировала механизм расширения форм. Разработчикам больше не нужно искать обходные пути только ради того, чтобы не заимствовать форму целиком. Механизм стал «мягким» и интеллектуальным.

Выясним, как работает этот механизм по шагам:

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

Проанализируем, как правильно написать обработчик события ПриИзменении для существующего реквизита формы этим способом:

  1. Добавляем форму в расширение конфигурации.
  2. Открываем модуль формы в расширении (он будет пустым).
  3. Используем аннотации для перехвата события. Для этого отлично подходят директивы &После или &Перед. Рассмотрим пример кода:

&После("ИмяРеквизитаПриИзменении")
Процедура Расш1_ИмяРеквизитаПриИзменении(Элемент)
    // Наш кастомный код, который выполнится после основного обработчика
    ПоказатьПредупреждение(, "Значение реквизита было успешно изменено!");
КонецПроцедуры

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

Решение 2. Использование механизма исправлений и патчей (Для платформы 8.3.15+)

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

Этот механизм позволяет изменять непосредственно строки кода модуля. Рассмотрим синтаксис специальных директив, которые применяются в модулях расширений-патчей:

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


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

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

Решение 3. Полностью программная модификация формы без её заимствования

Что делать, если перед нами стоит жесткое архитектурное требование: вообще не переносить форму в расширение (даже «мягким» способом)? В этом случае мы можем прибегнуть к программному изменению интерфейса и логики формы в момент её создания на сервере.

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

Рассмотрим пошагово, как реализовать этот алгоритм:

  1. Заимствуем в расширение не форму, а общий модуль (например, МодификацияКонфигурацииПереопределяемый) или создаем подписку на событие формы, если это применимо.
  2. В процедуре ПриСозданииНаСервере перехватываем управление для нужной формы по её имени.
  3. Программно добавляем новые элементы, реквизиты или изменяем свойства существующих элементов.

Однако здесь мы сталкиваемся с технической сложностью платформы. Если мы попытаемся программно назначить новый обработчик события для элемента формы с помощью метода УстановитьДействие, платформа потребует, чтобы процедура-обработчик физически находилась в модуле самой формы. Написать её туда без заимствования формы мы не можем.

Посмотрим, как обойти это ограничение через механизмы БСП:

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

Рассмотрим пример программного перехвата события создания формы на сервере в общем модуле расширения:


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

Этот способ самый сложный в реализации, так как требует глубокого понимания архитектуры БСП и программного создания интерфейса, но он гарантирует 100% чистоту конфигурации от лишних заимствованных объектов.

Резюме и рекомендации

Выбор оптимального метода зависит от конкретной задачи и версии платформы, на которой работает ваша информационная база:

← На главную