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