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

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

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

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

В чем заключается платформенное ограничение 1С?

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

Но если мы попытаемся проделать это программно через встроенный язык:


НоваяКнопка = Элементы.Добавить("КнопкаВыполнить", Тип("КнопкаФормы"), Элементы.КоманднаяПанель);
НоваяКнопка.ИмяКоманды = "ЖурналДокументов.СкладскиеДокументы.Команда.Перемещение"; // Вызовет ошибку!

Платформа 1С выдаст ошибку «Недопустимое значение». Свойство ИмяКоманды программно созданной кнопки формы может принимать исключительно имена локальных команд, зарегистрированных в коллекции Команды самой формы. Напрямую обратиться к глобальным или объектным командам встроенный язык не позволяет.

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

---

Решение 1. Использование декорации-надписи с навигационной ссылкой

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

Разберем по шагам логику построения такого интерфейсного элемента:

  1. Создаем декорацию на форме и указываем, что она должна отображаться в виде гиперссылки.
  2. Формируем специальную системную навигационную ссылку вида e1cib/command/<ПутьККоманде>.
  3. Помещаем эту ссылку в объект ФорматированнаяСтрока и назначаем её заголовком декорации.

Проанализируем пример кода, выполняемый на сервере:


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

При нажатии на такую декорацию платформа 1С автоматически распознает навигационную ссылку протокола e1cib и запустит выполнение команды.

Передача контекста (параметризация команды)

Если команда журнала документов должна открывать форму нового документа на основании выбранной строки списка, ей необходим параметр (ссылка на текущий документ). В навигационную ссылку можно динамически передавать параметры, используя синтаксис ?cmdprm=<Значение>.

Для реализации динамической передачи параметра нам потребуется обновлять ссылку при изменении активной строки списка. Рассмотрим пример доработки события ПриАктивизацииСтроки динамического списка:


&НаКлиенте
Процедура Расш_СписокПриАктивизацииСтрокиПосле(Элемент)
    
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        
        СсылкаНаОбъект = ТекущиеДанные.Ссылка;
        // Преобразуем ссылку в строковый идентификатор навигационной ссылки
        Идентификатор = ПолучитьНавигационнуюСсылку(СсылкаНаОбъект);
        
        // Находим созданную декорацию
        Декорация = Элементы.Найти("Расш_ДекорацияПеремещение");
        Если Декорация <> Неопределено Тогда
            
            // Формируем параметризованный адрес команды
            АдресКоманды = "e1cib/command/ЖурналДокументов.СкладскиеДокументы.Команда.Перемещение?cmdprm=" + Идентификатор;
            Декорация.Заголовок = Новый ФорматированнаяСтрока("Создать перемещение", , , , АдресКоманды);
            
        КонецЕсли;
        
    EndIf;
    
КонецПроцедуры

Преимущества метода: Полная независимость от формы. Форма не заимствуется в расширение.

Недостатки метода: Внешний вид элемента будет соответствовать текстовой гиперссылке, а не классической кнопке командной панели.

---

Решение 2. Заимствование только модуля формы (Создание локальной команды-посредника)

Если вам обязательно требуется полноценная кнопка (с заливкой, рамками, возможностью задать стандартную картинку 1С) и текстовая гиперссылка не подходит по требованиям UX/UI, применим метод «умного» заимствования.

Мы добавим форму списка журнала документов в наше расширение, но не будем изменять её визуально. Вся визуальная структура формы в расширении останется пустой (унаследованной от основной конфигурации), что исключит любые конфликты при обновлении. Мы задействуем только модуль формы для написания клиентского обработчика-посредника.

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

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

Рассмотрим реализацию серверной части в модуле формы:


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

Теперь опишем клиентскую часть в модуле формы, которая будет перехватывать нажатие и запускать нужную команду с контекстом текущей строки списка:


&НаКлиенте
Процедура Расш_ОбработчикКомандыПеремещение(Команда)
    
    // Получаем текущие данные из динамического списка
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    
    Если ТекущиеДанные <> Неопределено И ЗначениеЗаполнено(ТекущиеДанные.Ссылка) Тогда
        
        // Конструируем навигационную ссылку с параметром текущей строки
        НавСсылка = "e1cib/command/ЖурналДокументов.СкладскиеДокументы.Команда.Перемещение?cmdprm=" + ТекущиеДанные.Ссылка;
        
        // Выполняем переход, который активирует команду журнала документов
        ПерейтиПоНавигационнойСсылке(НавСсылка);
        
    КонецЕсли;
    
КонецПроцедуры

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

---

Решение 3. Использование механизма подключаемых команд БСП

Если вы работаете в современной типовой конфигурации 1С (например, 1С:ERP, 1С:Комплексная автоматизация, 1С:Управление торговлей или 1С:ЗУП), то в них «из коробки» внедрена Библиотека стандартных подсистем (БСП).

Подсистема БСП «Подключаемые команды» позволяет добавлять команды объектов и журналов на любые формы списков без ручного написания кода создания кнопок. Если форма списка журнала поддерживает БСП (то есть в её коде присутствует вызов ПодключаемыеКоманды.ПриСозданииНаСервере(ЭтотОбъект)), вы можете зарегистрировать свою команду в БСП.

Разберем основные шаги по интеграции команды через БСП:

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

Пример регистрации команды в модуле менеджера объекта для интеграции с БСП:


Процедура ДобавитьКомандыСозданияНаОсновании(ТаблицаКоманд) Экспорт
    
    Команда = ТаблицаКоманд.Добавить();
    Команда.Идентификатор = "Перемещение";
    Команда.Представление = НСтр("ru = 'Создать перемещение'");
    Команда.Порядок = 10;
    Команда.ЗаписыватьВерсиюНовогоОбъекта = Истина;
    Команда.РежимПроведенияСобытия = "Проводить";
    
КонецПроцедуры

При использовании БСП вам не придется писать ни одной строчки программного кода по манипуляции элементами формы списка. Платформа и подсистемы БСП сделают всю работу автоматически.

---

Сравнение и выбор оптимального метода

Выбор конкретного решения зависит от архитектуры вашей конфигурации и требований к дизайну:

← На главную