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