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