При разработке в среде 1С:Предприятие 8 начинающие программисты часто сталкиваются с необходимостью выполнить код, который уже написан и отлажен в модуле управляемой формы, но вызвать его нужно из модуля объекта или регламентного задания. На первый взгляд кажется удобным просто «нажать кнопку» программно, однако здесь мы упираемся в архитектурные ограничения платформы. Разберем подробно, почему прямой вызов невозможен и как правильно организовать архитектуру вашего решения.
Проанализируем ситуацию: когда выполняется регламентное задание, оно запускается в отдельном сеансе на сервере. В этом сеансе отсутствует пользовательский интерфейс. Платформа просто не инициализирует формы, так как их некому показывать. Модуль управляемой формы и его команды существуют только тогда, когда у конкретного пользователя открыто окно в тонком или толстом клиенте.
Серверный код (включая модуль объекта и фоновые задания) ничего не знает о том, что происходит на стороне клиента. Рассмотрим основные причины ограничений:
&НаКлиенте, а серверный код физически не может исполнять клиентские процедуры.Выясним причину, по которой код оказался в модуле формы. Чаще всего это происходит из-за удобства обращения к реквизитам формы. Однако правильный архитектурный подход по стандартам «1С» требует отделения логики манипуляции данными от интерфейса.
Рассмотрим по шагам, как перенести код для обеспечения его доступности отовсюду:
Шаг 1. Перенос кода в модуль объекта. Выделим алгоритм в отдельную экспортную процедуру в модуле объекта. Это позволит вызывать её и из формы, и из регламентного задания.
// В модуле объекта
Процедура ВыполнитьВажноеДействиеНаСервере() Экспорт
// Здесь размещаем бизнес-логику, которая раньше была в команде формы
ЭтотОбъект.Статус = Справочники.Статусы.Выполнено;
ЭтотОбъект.Записать();
КонецПроцедуры
Шаг 2. Вызов из формы. Теперь в модуле формы мы просто вызываем эту серверную процедуру объекта.
// В модуле формы
&НаСервере
Процедура КомандаВыполнитьНаСервере()
ОбъектДокумент = РеквизитВЗначение("Объект");
ОбъектДокумент.ВыполнитьВажноеДействиеНаСервере();
ЗначениеВРеквизит(ОбъектДокумент, "Объект");
КонецПроцедуры
Шаг 3. Вызов из регламентного задания. Теперь наше фоновое задание может легко выполнить ту же логику:
// В модуле объекта или общем модуле (регламентное задание)
Выборка = Документы.НашДокумент.Выбрать();
Пока Выборка.Следующий() Цикл
ОбъектДокумент = Выборка.Ссылка.ПолучитьОбъект();
ОбъектДокумент.ВыполнитьВажноеДействиеНаСервере();
КонецЦикла;
Иногда задача стоит иначе: регламентное задание что-то сделало, и нужно, чтобы у пользователя в уже открытой форме обновились данные или сработал какой-то визуальный эффект. Рассмотрим, как это реализовать через «Систему взаимодействия».
Посмотрим на пример отправки сообщения с сервера:
// Код на сервере (регламентное задание)
ВыбранныйПользователь = ПользователиИнформационнойБазы.НайтиПоИмени("Иван");
ПараметрыСообщения = Новый Структура("Действие", "ОбновитьФорму");
СистемаВзаимодействия.ОтправитьСообщение(ТекстСообщения, ВыбранныйПользователь, ПараметрыСообщения);
На стороне клиента в модуле формы должен быть настроен обработчик, который при получении сообщения выполнит команду &НаКлиенте. Это единственный способ «дотянуться» с сервера до живого интерфейса пользователя в реальном времени.
В обсуждениях часто упоминается возможность передачи формы в качестве параметра в серверные процедуры. Разберем этот нюанс. Это работает только в рамках одного сеанса. Если вы из формы вызываете серверную процедуру общего модуля, вы можете передать туда объект формы:
// В модуле формы
&НаКлиенте
Процедура ВыполнитьДействие()
МойОбщийМодуль.ОбработатьФорму(ЭтаФорма);
КонецПроцедуры
// В общем модуле
Процедура ОбработатьФорму(ФормаОбъекта) Экспорт
// Здесь мы можем обратиться к экспортным методам формы
ФормаОбъекта.ОбновитьДанныеНаКлиенте();
КонецПроцедуры
Важно: Для этого процедура ОбновитьДанныеНаКлиенте в модуле формы должна быть помечена как Экспорт. Однако помните, что для регламентного задания этот метод бесполезен, так как никакой «ФормыОбъекта» в его сеансе не существует.
Проанализируем ситуацию, когда Система взаимодействия не подключена. Мы можем использовать механизм опроса (polling). Форма будет периодически «спрашивать» базу данных: «Не сделало ли регламентное задание что-то важное для меня?».
Для этого используем метод ПодключитьОбработчикОжидания:
ПриОткрытии на клиенте подключаем обработчик (например, раз в 30 секунд).Подведем итог: никогда не пытайтесь вызвать интерфейсные методы из фоновых процессов напрямую. Единственно верный путь — вынос общей логики в Модуль объекта или Общий модуль, что делает код чистым, тестируемым и независимым от контекста исполнения.