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