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