Принцип работы довольно прост. Из основной конфигурации добавлены два общих модуля:
1. ПодключаемыеКоманды.
&После("ПриСозданииНаСервере")
Процедура Т_Ы_К_ПриСозданииНаСервере(Форма, Знач ПараметрыРазмещения)
Т_Ы_К_СлужебныеПроцедурыФункцииСервер.ОпределитьПодключенныйОбъект(Форма, ПараметрыРазмещения);
КонецПроцедуры
Данная процедура ссылается на модуль расширения "Т_Ы_К_СлужебныеПроцедурыФункцииСервер". В нем прописана основная логика: сначала определяется полное имя объекта с помощью функции "ПолучитьПолноеИмяОбъекта", а после этого запросом ищем, есть ли элемент, который необходимо создать на форме для данного объекта. В этом примере в качестве объекта будет служить документ "Служебная записка", а элемент — это кнопка, свойства которой описаны в справочнике "Т_Ы_К_Кнопки".
Процедура ОпределитьПодключенныйОбъект(Форма, Знач ПараметрыРазмещения) Экспорт
ИмяФормы = Форма.ИмяФормы;
ПолноеИмяОбъекта = ПолучитьПолноеИмяОбъекта(ИмяФормы);
УникальныйИдентификаторОбъекта = Форма.УникальныйИдентификатор;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Т_Ы_К_КнопкиПодключенныеОбъекты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Т_Ы_К_Кнопки.ПодключенныеОбъекты КАК Т_Ы_К_КнопкиПодключенныеОбъекты
|ГДЕ
| Т_Ы_К_КнопкиПодключенныеОбъекты.Подключен = ИСТИНА
| И Т_Ы_К_КнопкиПодключенныеОбъекты.ПолноеИмяОбъекта = &ПолноеИмяОбъекта";
Запрос.УстановитьПараметр("ПолноеИмяОбъекта", ПолноеИмяОбъекта);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Количество() Тогда
Выборка.Следующий();
Ссылка = Выборка.Ссылка;
Команда = Форма.Команды.Добавить(Ссылка.Наименование);
Команда.Заголовок = Ссылка.ЗаголовокКоманды;
Команда.Отображение = ОтображениеКнопки.Авто;
Команда.Действие = "Подключаемый_ВыполнитьКоманду";
Команда.ИзменяетСохраняемыеДанные = Истина;
НовыйЭлемент = Форма.Элементы.Добавить(Ссылка.Наименование, Тип("КнопкаФормы"), Форма.КоманднаяПанель);
НовыйЭлемент.Вид = ВидКнопкиФормы[Строка(Ссылка.Вид)];
НовыйЭлемент.ИмяКоманды = Ссылка.Наименование;
НовыйЭлемент.Заголовок = Ссылка.ЗаголовокКоманды;
КонецЕсли;
КонецПроцедуры
Функция ПолучитьПолноеИмяОбъекта(ИмяФормы)
ПрерватьЦикл = Ложь;
ПолноеИмяОбъекта = "";
Для Счетчик = 1 По СтрДлина(ИмяФормы) Цикл
Символ = Прав(Лев(ИмяФормы, Счетчик), 1);
Если Символ = "." Тогда
Если ПрерватьЦикл Тогда
Прервать;
КонецЕсли;
ПрерватьЦикл = Истина;
КонецЕсли;
ПолноеИмяОбъекта = ПолноеИмяОбъекта + Символ;
КонецЦикла;
Возврат ПолноеИмяОбъекта;
КонецФункции
Данная функция будет срабатывать каждый раз, когда мы открываем форму списка или форму документа, и будет создавать элемент на форме при наличии его описания (элементом может быть не только кнопка, но и любой другой элемент формы).
Вот так выглядит описание элемента в моем случае:

Код кнопки на сервере:

Сверху находятся основные свойства кнопки, далее идет код, который выполняет кнопка на клиенте и на сервере (о том, как это реализовано, будет далее), и объекты, в которых эта кнопка будет рисоваться при открытии формы.
Форма списка:

Результат:

Теперь что касается того, как выполняется код написанный для данной кнопки.
2. ПодключаемыеКомандыКлиент.
В данном модуле есть процедура "НачатьВыполнениеКоманды" (для удобства использую <ИзменениеИКонтроль>):
&ИзменениеИКонтроль("НачатьВыполнениеКоманды")
Процедура Т_Ы_К_НачатьВыполнениеКоманды(Форма, Команда, Знач Источник)
#Вставка
Результат = Т_Ы_К_СлужебныеПроцедурыФункцииКлиент.ВыполнитьПользовательскуюКоманду(Форма, Команда, Источник);
Если Результат Тогда
Возврат;
КонецЕсли;
#КонецВставки
ИмяКоманды = Команда.Имя;
АдресНастроек = Форма.ПараметрыПодключаемыхКоманд.АдресТаблицыКоманд;
ОписаниеКоманды = ПодключаемыеКомандыКлиентПовтИсп.ОписаниеКоманды(ИмяКоманды, АдресНастроек);
Если Источник = Неопределено Тогда
Источник = ПодключаемыеКомандыКлиентСервер.ВладелецКомандыПоИмениКоманды(ИмяКоманды, Форма);
КонецЕсли;
ПараметрыВыполнения = ПараметрыВыполненияКоманды();
ПараметрыВыполнения.ОписаниеКоманды = Новый Структура(ОписаниеКоманды);
ПараметрыВыполнения.Форма = Форма;
ПараметрыВыполнения.Источник = Источник;
ПараметрыВыполнения.ЭтоФормаОбъекта = ТипЗнч(Источник) = Тип("ДанныеФормыСтруктура");
// Служебные параметры.
ПараметрыВыполнения.ТребуетсяЗапись = ПараметрыВыполнения.ЭтоФормаОбъекта И ОписаниеКоманды.РежимЗаписи <> "НеЗаписывать";
ПараметрыВыполнения.ТребуетсяПроведение = ОписаниеКоманды.РежимЗаписи = "Проводить"
И (Не ПараметрыВыполнения.ЭтоФормаОбъекта Или Источник.Свойство("Проведен"));
ПараметрыВыполнения.ТребуетсяРаботаСФайлами = ОписаниеКоманды.ТребуетсяРаботаСФайлами;
ПараметрыВыполнения.ВызовСервераЧерезОбработкуОповещения = Истина;
ПродолжитьВыполнениеКоманды(ПараметрыВыполнения);
КонецПроцедуры
Процедура как раз срабатывает при нажатии на нашу кнопку, и мы ловим этот момент и перенаправляем на еще один модуль расширения "Т_Ы_К_СлужебныеПроцедурыФункцииКлиент":
Функция ВыполнитьПользовательскуюКоманду(Форма, Команда, Источник) Экспорт
СтруктураДанных = Т_Ы_К_СлужебныеПроцедурыФункцииСервер.ПолучитьДанныеКнопкиПоИмени(Команда.Имя);
Если СтруктураДанных.Количество() Тогда
Попытка
Выполнить(СтруктураДанных.ВыполняемыйКодНаКлиенте);
Исключение
Сообщить(ОписаниеОшибки());
Т_Ы_К_СлужебныеПроцедурыФункцииСервер.СделатьЗаписьВЖурналРегистрации("Недопустимый код в пользовательской команде на клиенте", СтруктураДанных.ВыполняемыйКодНаКлиенте);
Возврат Истина;
КонецПопытки;
Попытка
Т_Ы_К_СлужебныеПроцедурыФункцииСервер.ВыполнитьКодНаСервере(СтруктураДанных.ВыполняемыйКодНаСервере);
Исключение
Сообщить(ОписаниеОшибки());
Т_Ы_К_СлужебныеПроцедурыФункцииСервер.СделатьЗаписьВЖурналРегистрации("Недопустимый код в пользовательской команде на сервере", СтруктураДанных.ВыполняемыйКодНаСервере);
Возврат Истина;
КонецПопытки;
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;
КонецФункции
Сначала ищем по имени кнопку, далее подтягиваем пользовательский код команды в структуру, а исполнение кода происходит с помощью метода "Выполнить".
Также процедуры из модуля "Т_Ы_К_СлужебныеПроцедурыФункцииСервер", на которые ссылается данный код:
Функция ПолучитьДанныеКнопкиПоИмени(ИмяКнопки) Экспорт
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Т_Ы_К_Кнопки.Код КАК Код,
| Т_Ы_К_Кнопки.ЗаголовокКоманды КАК ЗаголовокКоманды,
| Т_Ы_К_Кнопки.Вид КАК Вид,
| Т_Ы_К_Кнопки.ВыполняемыйКодНаКлиенте КАК ВыполняемыйКодНаКлиенте,
| Т_Ы_К_Кнопки.ВыполняемыйКодНаСервере КАК ВыполняемыйКодНаСервере
|ИЗ
| Справочник.Т_Ы_К_Кнопки КАК Т_Ы_К_Кнопки
|ГДЕ
| Т_Ы_К_Кнопки.Наименование = &Наименование";
Запрос.УстановитьПараметр("Наименование", ИмяКнопки);
Выборка = Запрос.Выполнить().Выбрать();
СтруктураДанных = Новый Структура;
Пока Выборка.Следующий() Цикл
СтруктураДанных.Вставить("Код", Выборка.Код);
СтруктураДанных.Вставить("ЗаголовокКоманды", Выборка.ЗаголовокКоманды);
СтруктураДанных.Вставить("Вид", Выборка.Вид);
СтруктураДанных.Вставить("ВыполняемыйКодНаКлиенте", Выборка.ВыполняемыйКодНаКлиенте);
СтруктураДанных.Вставить("ВыполняемыйКодНаСервере", Выборка.ВыполняемыйКодНаСервере);
КонецЦикла;
Возврат СтруктураДанных;
КонецФункции
Процедура ВыполнитьКодНаСервере(ВыполняемыйКодНаСервере) Экспорт
Выполнить(ВыполняемыйКодНаСервере);
КонецПроцедуры
Процедура СделатьЗаписьВЖурналРегистрации(Ошибка, ИмяСобытия, ВыполняемыйКод) Экспорт
ЗаписьЖурналаРегистрации(ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, Метаданные.Справочники.Т_Ы_К_Кнопки,, ВыполняемыйКод);
КонецПроцедуры
Таким образом, данный подход является наглядным примером использования возможностей механизма подключения команд библиотеки стандартных подсистем для создания низкозатратных и легко конфигурируемых пользовательских доработок.
Проверено на следующих конфигурациях и релизах:
- 1С:ERP Управление предприятием 2, релизы 2.5.22.159
Вступайте в нашу телеграмм-группу Инфостарт