При разработке и сопровождении конфигураций на платформе 1С:Предприятие 8.3 (особенно в режиме обычного приложения) перед программистом нередко возникает задача внедрения сквозного функционала. Например, требуется добавить сервисную кнопку («Заполнить», «Проверить», «Отправить в архив») абсолютно во все формы документов или справочников. Изменять каждую форму вручную — это колоссальные временные затраты и существенные сложности при последующих обновлениях конфигурации. Гораздо эффективнее реализовать эту задачу программно.
В рамках этой статьи мы подробно разберем, как решить данную задачу красивым и технологичным способом, проанализируем основные ошибки начинающих разработчиков и выясним, почему созданные динамически кнопки часто оказываются неактивными.
Рассмотрим ситуацию, с которой часто сталкиваются программисты при попытке добавить кнопку из общего модуля. Код успешно отрабатывает, кнопка визуально появляется на командной панели формы, но при этом она остается «серой» (неактивной), и нажать на нее невозможно. Выясним, почему это происходит.
Для создания кнопки и привязки действия в обычном приложении традиционно используется следующий шаблон кода:
КоллекцияКнопок = ФормаДокумента.ЭлементыФормы.ДействияФормы.Кнопки;
ДействиеОткрытияФормы = Новый Действие("ВыполнитьДействиеНажатие");
НоваяКнопка = КоллекцияКнопок.Добавить("ВыполнитьДействиеНажатие", ТипКнопкиКоманднойПанели.Действие, "Выполнить действие", ДействиеОткрытияФормы);
Если кнопка отображается неактивной, дело в одной из двух фундаментальных причин платформы 1С:
КнопкаКоманднойПанели). Если процедура объявлена без параметров (например, Процедура ВыполнитьДействиеНажатие()), платформа считает ее неподходящей для данного действия и автоматически блокирует кнопку.Новый Действие("ИмяПроцедуры") платформа ищет указанную процедуру строго в определенных модулях. Если процедура расположена в общем модуле, платформа не сможет ее вызвать напрямую через конструкцию вида Новый Действие("ОбщийМодуль.ИмяПроцедуры"). Такой вызов завершится ошибкой выполнения или сделает кнопку недоступной.Проанализируем, как обойти ограничение видимости процедур и заставить кнопку работать без необходимости вставки кода в модуль каждой отдельной формы.
Согласно архитектуре обычного приложения 1С, объект Действие видит экспортные процедуры, расположенные либо непосредственно в модуле самой формы, либо в модуле обычного приложения (глобальный контекст).
Поскольку наша цель — избежать редактирования сотен форм, мы воспользуемся возможностями модуля обычного приложения. Выполним следующие шаги:
Шаг 1. Объявление глобального обработчика. Откроем модуль обычного приложения вашей конфигурации и добавим туда экспортную процедуру с правильной сигнатурой:
Процедура ГлобальныйОбработчикНажатияКнопки(Кнопка) Экспорт
// Здесь размещается логика, которая должна выполняться при нажатии.
// Для определения контекста (какая именно форма вызвала действие) можно использовать активное окно:
ТекущаяФорма = ПолучитьАктивноеОкно().Содержимое;
Если ТипЗнч(ТекущаяФорма) = Тип("Форма") Тогда
Предупреждение("Кнопка нажата на форме: " + ТекущаяФорма.Заголовок);
// Далее можно выполнять любые действия с реквизитами формы или ее объектом
КонецЕсли;
КонецПроцедуры
Обратите внимание на параметр Кнопка. Его наличие гарантирует, что платформа распознает процедуру как валидный обработчик нажатия, и кнопка станет активной.
Шаг 2. Динамическое добавление кнопки. Теперь нам нужно найти общую точку входа — процедуру, которая вызывается при открытии любого документа или справочника в системе. В типовых конфигурациях (например, УТ 10.3, УПП 1.3, КА 1.1) для этого идеально подходит общий модуль РаботаСДиалогами.
Найдем в модуле РаботаСДиалогами процедуру УстановитьЗаголовокФормыДокумента(Форма, ТекстЗаголовка = "") или аналогичную ей (например, УстановитьОформлениеЭкранныхЭлементов), которая гарантированно вызывается при инициализации интерфейса документов. Добавим в нее вызов нашей функции внедрения кнопки:
Процедура ДобавитьКнопкуНаПанельФормы(Форма) Экспорт
// Проверяем наличие командной панели "ДействияФормы"
ПанельДействий = Форма.ЭлементыФормы.Найти("ДействияФормы");
Если ПанельДействий <> Неопределено И ТипЗнч(ПанельДействий) = Тип("КоманднаяПанель") Тогда
// Проверим, не добавлена ли кнопка ранее, чтобы избежать дублирования
ИмяКнопки = "КнопкаГлобальногоДействия";
Если ПанельДействий.Кнопки.Найти(ИмяКнопки) = Неопределено Тогда
// Создаем объект Действие, указывая имя глобальной процедуры из Модуля обычного приложения
НовоеДействие = Новый Действие("ГлобальныйОбработчикНажатияКнопки");
// Добавляем кнопку на панель
ПанельДействий.Кнопки.Добавить(
ИмяКнопки,
ТипКнопкиКоманднойПанели.Действие,
"Сервис",
НовоеДействие
);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Аналогичным образом мы можем поступить и со справочниками. Достаточно вызвать разработанный метод из процедуры общего модуля РаботаСДиалогами.УстановитьЗаголовокФормыСправочника.
В процессе обсуждения на форумах часто возникает вопрос: «Можно ли решить эту задачу изящнее, например, через подписку на событие формы?». Ответ однозначный — в обычном приложении это сделать невозможно.
Разберем причины этого ограничения подробнее. Механизм подписок на события в платформе 1С ориентирован исключительно на работу с прикладными объектами базы данных (такими как ДокументОбъект, СправочникОбъект, РегистрНаборЗаписей). События, на которые можно подписаться (например, ПередЗаписью, ПриЗаписи, ОбработкаПроверкиЗаполнения), исполняются на уровне данных. На этом уровне у системы нет доступа к визуальным элементам интерфейса и формам.
События форм (такие как ПриОткрытии, ПриСозданииНаСервере) поддерживают подписку только начиная с управляемого интерфейса (платформа 8.3, управляемые формы) через событие ПриСозданииНаСервере в переопределяемых модулях. В обычных формах подписки на события интерфейса отсутствуют как класс, поэтому динамическое вмешательство через общий модуль при инициализации форм (как показано в шаге 2) остается единственным работоспособным системным решением.
Если вы хотите избежать внесения изменений в конфигурацию и сохранить ее полностью на поддержке, рассмотрим отличную альтернативу — использование механизма дополнительных внешних обработок заполнения табличных частей.
В типовых конфигурациях на обычных формах встроен механизм, который автоматически сканирует зарегистрированные внешние обработки заполнения. Если для документа зарегистрирована такая обработка, система самостоятельно:
Этот способ имеет неоспоримое преимущество: конфигурация остается полностью типовой, что существенно облегчает процесс обновления, а вся сервисная логика выносится во внешний файл обработки (.epf).