При разработке на управляемых формах в 1С часто возникает ситуация, когда логика, заложенная в общую команду объекта (например, команду "Выгрузить"), требуется не только при нажатии пользователем на кнопку в командной панели, но и программно — например, при срабатывании горячей клавиши в форме или при выполнении определенного алгоритма. Давайте разберем, почему попытка прямого вызова обработчика команды приведет к ошибке и как реализовать эту задачу правильно, следуя стандартам разработки 1С.
Начнем с анализа архитектурных ограничений платформы 1С:Предприятие 8.3. Когда мы создаем команду документа, ее программный код размещается в Модуле команды. Этот модуль имеет специфическую область видимости. Разберем основные причины, по которым конструкция типа Документы.МойДок.Команды.Выгрузить.ОбработкаКоманды() не будет работать:
ОбработкаКоманды всегда ожидает два обязательных параметра: ПараметрКоманды (обычно ссылка или массив ссылок) и ПараметрыВыполненияКоманды. Последний параметр является объектом типа ОписаниеПараметровВыполненияКоманды, который заполняется платформой автоматически и содержит данные о контексте UI (уникальный идентификатор формы, окно, URL и т.д.). Эмулировать этот объект вручную крайне сложно и нецелесообразно.Рассмотрим, как решить задачу изящно, используя методику разделения ответственности.
Наиболее правильным и "красивым" с точки зрения архитектуры решением является вынос всей бизнес-логики из модуля команды в Модуль менеджера документа. Это позволяет обращаться к коду из любой точки конфигурации: из формы, из самой команды, из фоновых заданий или даже через внешнее соединение.
Разберем по шагам, как это реализовать:
Шаг 1. Перенос кода в Модуль менеджера. Находим наш документ в дереве конфигурации, открываем модуль менеджера и создаем там экспортную процедуру:
// В модуле менеджера документа
Процедура ВыполнитьВыгрузку(СсылкаНаДокумент) Экспорт
// Здесь размещается основной код выгрузки
// Например, формирование файла или отправка в API
Сообщить("Выполняется выгрузка документа: " + СсылкаНаДокумент);
КонецПроцедуры
Шаг 2. Вызов из модуля команды. Теперь код в модуле самой команды станет предельно лаконичным. Он будет просто передавать управление в модуль менеджера:
// В модуле команды
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
// ПараметрКоманды содержит ссылку на текущий документ
Документы.МойДокумент.ВыполнитьВыгрузку(ПараметрКоманды);
КонецПроцедуры
Шаг 3. Вызов из формы документа по горячей клавише. Теперь мы можем легко реализовать требование автора темы. В форме документа создаем команду формы, назначаем ей горячую клавишу (например, Ctrl+Shift+E) и прописываем вызов того же метода:
// В модуле формы документа
&НаКлиенте
Процедура ОбработкаГорячейКлавишиВыгрузки(Команда)
// Сначала записываем и проводим документ, как требовалось
Если Объект.Ссылка.Пустая() Или ЭтаФорма.Модифицированность Тогда
Если Не Записать(Новый Структура("РежимЗаписи", РежимЗаписиДокумента.Проведение)) Тогда
Возврат; // Если проведение не удалось, прерываем
КонецЕсли;
КонецЕсли;
// Вызываем общую логику из модуля менеджера
// Так как метод в модуле менеджера доступен через сервер,
// вызываем его в контексте сервера
ВыполнитьВыгрузкуНаСервере(Объект.Ссылка);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ВыполнитьВыгрузкуНаСервере(Ссылка)
Документы.МойДокумент.ВыполнитьВыгрузку(Ссылка);
КонецПроцедуры
Этот подход гарантирует, что логика выгрузки едина и не дублируется, а вызов происходит прозрачно и надежно.
Проанализируем ситуацию, когда нам всё же крайне важно "дернуть" именно клиентскую команду. Хотя это менее предпочтительно, мы можем использовать метод Оповестить(). Это может быть полезно, если в команде заложена сложная работа с интерактивными окнами (например, открытие диалогов выбора файлов), которую сложно перенести в модуль менеджера.
В этом случае в модуле команды мы можем подписаться на событие:
// В модуле формы, которая должна инициировать действие
&НаКлиенте
Процедура НажатьКнопкуПрограммно()
Оповестить("ЗапуститьВыгрузку", Объект.Ссылка);
КонецПроцедуры
Однако стоит учитывать, что стандартные Команды объекта не умеют "слушать" оповещения платформы. Метод Оповестить работает между формами. Поэтому, если вам нужно программно запустить именно интерфейсное действие, лучше создать Команду формы, которая будет доступна через контекст ЭтаФорма.ВыполнитьКоманду("ИмяКоманды").
Выясним причину, почему разработчики платформы не реализовали прямой вызов Команды.Выгрузить.Выполнить(). Команды в управляемом приложении — это элементы интерфейса, а не данных. Модуль команды — это клиентский код. Вызывая его "программно" из кода, который может выполняться на сервере, мы бы нарушили базовый принцип клиент-серверного взаимодействия.
Подведем итог:
ОбработкаКоманды() напрямую — это тупиковый путь.Модуль менеджера (для логики без UI) или в Общий модуль.Таким образом, разделяя интерфейс (кнопки и команды) и суть процесса (алгоритм выгрузки), мы получаем чистый и поддерживаемый код, соответствующий стандартам разработки 1С. Для быстрого оформления кода по правилам платформы пригодятся шаблоны для применения стандартов и методик разработки конфигураций 1С.