Как программно добавить кнопку на форму с вызовом процедуры из общего модуля?

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

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

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

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

Почему стандартный подход не работает?

Проанализируем типовую ошибку, которую часто совершают программисты при попытке решить задачу «в лоб». В общем модуле пишется следующий код:


&НаКлинете
Процедура ДобавитьКнопкуНаФорму(Форма) Экспорт
    Команда = Форма.Команды.Добавить("МояКоманда");
    Команда.Действие = "ИмяОбщегоМодуля.ДействиеПоКнопке"; // Ошибка!
    
    Кнопка = Форма.Элементы.Добавить("МояКнопка", Тип("КнопкаФормы"), Форма.Элементы.ФормаКоманднаяПанель);
    Кнопка.Заголовок = "Моя кнопка";
    Кнопка.ИмяКоманды = "МояКоманда";
КонецПроцедуры

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

Для обхода этого ограничения существует несколько проверенных архитектурных решений.

---

Решение 1. Использование встроенного механизма БСП «Подключаемые команды» (Рекомендуемый способ)

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

Рассмотрим по шагам, как зарегистрировать свою команду через БСП:

  1. Найдем в конфигурации общий переопределяемый модуль ПодключаемыеКомандыПереопределяемый и процедуру ПриОпределенииКомандПодключенныхКОбъекту.
  2. В этой процедуре мы можем программно зарегистрировать нашу команду для нужных типов документов:

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

Процедура ВыполнитьДействиеПоКнопке(Знач МассивСсылок, Знач ПараметрыВыполнения) Экспорт
    
    // Получаем контекст формы, из которой была нажата кнопка
    Форма = ПараметрыВыполнения.Форма;
    
    // Здесь пишем любую логику работы с формой и данными
    ПоказатьПредупреждение(, "Кнопка успешно нажата из документа: " + Форма.Объект.Ссылка);
    
КонецПроцедуры

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

---

Решение 2. Перехват стандартного обработчика БСП через расширение (Быстрый лайфхак)

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

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

Разберем этот метод по шагам:

  1. В общем модуле при инициализации формы программно добавляем команду и кнопку. В качестве действия указываем стандартный метод формы:

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

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

Этот способ невероятно изящен: мы не изменяем модули 200 форм документов, не регистрируем новые команды в БСП, а просто вклиниваемся в стандартный механизм маршрутизации платформы.

---

Решение 3. Использование объекта метаданных «Общая команда»

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

Рассмотрим порядок настройки общей команды:

  1. В дереве метаданных конфигурации (или в расширении) создайте новую Общую команду (например, ВыполнитьГрупповуюОбработку).
  2. В свойствах созданной команды найдите параметр Тип параметра команды. Нажмите на три точки и отметьте галочками все те типы документов (из ваших 200), на формах которых должна отображаться кнопка. Также можно использовать Определяемый тип, если он объединяет нужные документы.
  3. В свойстве Группа укажите, где должна отображаться кнопка, например: Командная панель формы.Важное или Командная панель формы.Еще.
  4. В модуле общей команды напишите обработчик, который будет вызываться при нажатии кнопки:

&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
    
    // ПараметрКоманды содержит ссылку на документ, из формы которого была нажата кнопка.
    // ПараметрыВыполненияКоманды.Источник хранит контекст самой управляемой формы.
    
    ФормаДокумента = ПараметрыВыполненияКоманды.Источник;
    
    // Вызываем логику из нашего общего модуля
    МойОбщийМодульКлиент.ОбработатьДокумент(ПараметрКоманды, ФормаДокумента);
    
КонецПроцедуры

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

Минусы подхода: Кнопка может автоматически появиться не только на формах элементов документов, но и в формах списков (если тип параметра команды совпадает). Если показ кнопки в списках нежелателен, в модуле общей команды придется делать дополнительную проверку на тип источника или использовать программные способы сокрытия кнопки.

---

Резюме

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

← На главную