Работа с формой объекта в серверном коде 1С 8.3
Содержание
Получить управляемую форму как самостоятельный объект на сервере в 1С:Предприятие 8.3 нельзя — метод ПолучитьФорму() выполняется только на клиенте. На сервере вы работаете не с «формой целиком», а с её контекстом: внутри серверных процедур самой формы к ней обращаются через ЭтотОбъект, реквизиты превращают в прикладные объекты через РеквизитФормыВЗначение(), а события ловят в процедурах с директивой &НаСервере.
Это ограничение архитектурное, а не ошибка. Разделение на клиент и сервер в управляемом приложении устроено так, что визуальная форма живёт на клиенте, а сервер оперирует данными. Поэтому вопрос «как получить форму на сервере» на практике распадается на несколько разных задач, и для каждой есть свой приём.
Ниже — где метод ПолучитьФорму работает, что именно доступно в серверном коде формы, как передать и прочитать параметры, как обрабатывать серверные события и почему в фоновом задании форму взять в принципе невозможно.
Почему управляемую форму нельзя взять на сервере как объект
В управляемом приложении клиент и сервер физически разделены. Форма — это элемент интерфейса: кнопки, поля, таблицы, события ввода. Всё это отображается и реагирует на действия пользователя на клиенте (тонком, веб- или толстом). Сервер интерфейс не рисует и мышь не слушает — он выполняет запросы, читает и пишет данные, проверяет права.
Из-за этого объект УправляемаяФорма существует на стороне клиента. Сервер «видит» форму только в один момент: когда с клиента вызывается серверная процедура этой же формы. На время такого вызова платформа передаёт на сервер контекст формы — её реквизиты и настройки элементов, — а после возврата отправляет изменения обратно на клиент.
Отсюда вытекает главное правило: получить произвольную «чужую» форму на сервере невозможно. Доступна только та форма, из серверной процедуры которой вы сейчас находитесь.
Монопольный доступ и прочие тонкости платформы здесь ни при чём — ограничение чисто архитектурное и действует всегда, независимо от режима запуска.
Что доступно внутри серверных процедур формы
Когда вы пишете процедуру с директивой &НаСервере в модуле формы, у вас есть доступ к самой форме и её содержимому.
- 🔹
ЭтотОбъект— ссылка на текущую управляемую форму. В модуле формы это и есть «форма» в серверном коде. - 🔹
Элементы— коллекция элементов (поля, группы, таблицы, кнопки). На сервере можно менять их свойства:Видимость,Доступность,ТолькоПросмотр, заголовки. - 🔹 Реквизиты формы — обращение по имени напрямую, например
Объект,СписокТоваров, ваши служебные реквизиты. - 🔹
Параметры— параметры, с которыми форму открыли (надёжно доступны в момент создания формы).
Пример процедуры создания формы, которая настраивает её на сервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// ЭтотОбъект — сама управляемая форма
ЭтотОбъект.Заголовок = "Карточка: " + Строка(Параметры.Ключ);
// Управляем элементами прямо на сервере
Элементы.Комментарий.Видимость = Ложь;
Элементы.СуммаДокумента.ТолькоПросмотр = Истина;
КонецПроцедуры
Важная оговорка про директивы. Доступ к форме есть только у процедур &НаСервере — они выполняются с контекстом формы. Процедуры &НаСервереБезКонтекста работают без контекста формы: в них нет ни ЭтотОбъект, ни Элементы, ни реквизитов. Это сделано ради производительности: такой вызов не гоняет контекст формы на сервер и обратно. Если вам внутри нужен доступ к форме — директива должна быть именно &НаСервере.
&НаСервереБезКонтекста быстрее, но «не видит» форму. Не пытайтесь обращаться там к ЭтотОбъект — получите ошибку, что переменная не определена.
Отдельно про управляемые и обычные формы. Всё сказанное выше — про управляемые формы 1С:Предприятие 8.3, которые разделены на клиент и сервер. Обычные формы (наследие версий 8.1–8.2, режим обычного приложения) устроены иначе: там форма — единый объект без строгого деления на контексты, и код выполняется в общем пространстве. Если конфигурация работает в режиме управляемого приложения — а это все современные типовые решения, — вас касается именно управляемая модель. Переносить на неё приёмы обычных форм (прямое обращение к форме из любого места) нельзя: в управляемом приложении это не скомпилируется.
Ещё один нюанс управляемых форм: изменения элементов, сделанные на сервере, доходят до пользователя не сразу, а после возврата управления на клиент. Поэтому настройку внешнего вида (видимость, доступность, заголовки) делают разом в серверной процедуре, а не «по кусочкам» в середине длинного расчёта — всё равно клиент увидит только итоговое состояние.
Метод ПолучитьФорму: клиентский вызов и его параметры
Сам метод ПолучитьФорму() возвращает объект формы, но вызывается он на клиенте. Его назначение — получить форму, не открывая её сразу, чтобы предварительно что-то в ней настроить, а потом вызвать Открыть().
&НаКлиенте
Процедура ОткрытьКарточкуЗаказа(СсылкаНаЗаказ)
Форма = ПолучитьФорму("Документ.ЗаказПокупателя.ФормаОбъекта",
Новый Структура("Ключ", СсылкаНаЗаказ));
// при необходимости настраиваем форму до показа
Форма.Открыть();
КонецПроцедуры
Основные параметры метода:
| Параметр | Назначение |
|---|---|
| Имя формы | Полное имя: Документ.ИмяДокумента.ФормаОбъекта |
| Параметры | Структура параметров открытия (Ключ, Отбор и др.) |
| Владелец | Форма-владелец (для связи и уникальности) |
| Уникальность | Ключ уникальности окна |
| Окно | В каком окне показывать |
Если вам нужно просто открыть форму, обычно удобнее ОткрытьФорму() — он сразу и получает, и показывает. ПолучитьФорму() берут тогда, когда между получением и открытием нужно выполнить дополнительные действия.
Оба метода — ПолучитьФорму и ОткрытьФорму — клиентские. В серверной процедуре конфигуратор подчеркнёт их вызов и сообщит, что метод в этом контексте недоступен.
Как передать параметры и прочитать контекст формы на сервере
Чтобы форма «знала», с каким объектом её открыли, при открытии ей передают структуру параметров. Стандартный параметр для формы объекта — Ключ (ссылка на элемент или документ). Есть и другие: ЗначениеКопирования, Основание, Отбор, ПараметрКоманды.
На сервере эти значения читают из коллекции Параметры в обработчике ПриСозданииНаСервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("Основание")
И ЗначениеЗаполнено(Параметры.Основание) Тогда
ЗаполнитьПоОснованию(Параметры.Основание);
КонецЕсли;
КонецПроцедуры
Коллекцию Параметры надёжно читать именно в момент создания формы. После того как форма создана, обращаться к ней как к источнику данных не стоит — используйте для хранения собственные реквизиты формы.
Если нужно передать на сервер не весь контекст, а отдельные значения (ради скорости), их отправляют аргументами в процедуру &НаСервереБезКонтекста. Так делают для тяжёлых операций, которым форма целиком не нужна.
На практике выбор такой: нужна вся форма с реквизитами и элементами — берите &НаСервере; нужен только расчёт по нескольким входным значениям — выносите его в &НаСервереБезКонтекста и передавайте аргументы явно. Второй вариант не гоняет лишние данные между клиентом и сервером и заметно экономит трафик на нагруженных формах с большими табличными частями.
Серверные обработчики событий формы
«Обработка событий формы в серверном потоке» — это стандартные серверные обработчики, которые платформа вызывает в определённые моменты жизни формы. У каждого есть версия НаСервере.
ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)— форма создаётся. Здесь настраивают элементы, читают параметры, заполняют реквизиты.ПриЧтенииНаСервере(ТекущийОбъект)— объект прочитан из базы. Удобно донастроить форму под прочитанные данные.ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)— перед записью объекта.ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)— в момент записи, внутри транзакции.ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)— после записи.ОбработкаПроверкиЗаполненияНаСервере(Отказ, ПроверяемыеРеквизиты)— серверная проверка заполнения.
&НаСервере
Процедура ПриЧтенииНаСервереПослеЧтения(ТекущийОбъект)
// донастраиваем форму под уже прочитанный объект
Элементы.ПричинаАннулирования.Видимость =
(ТекущийОбъект.Состояние = Перечисления.Состояния.Аннулирован);
КонецПроцедуры
Ключевое отличие от клиентских событий: серверные обработчики не умеют общаться с пользователем. Нельзя показать Вопрос() или Предупреждение(), нельзя ждать ответа. Диалоги и реакция на ввод — только в клиентских процедурах &НаКлиенте. Сервер меняет данные и настройки, клиент — разговаривает с пользователем.
Преобразование реквизитов формы в объект и обратно
Частая настоящая задача за формулировкой «получить форму на сервере» звучит иначе: получить на сервере не форму, а прикладной объект, который на форме редактируется. Данные формы хранятся в особой структуре (данные формы), и напрямую как объект их не использовать. Для перевода есть пара методов, доступных в &НаСервере:
РеквизитФормыВЗначение(ИмяРеквизита, Тип)— превращает реквизит формы в прикладной объект (документ, элемент справочника).ЗначениеВРеквизитФормы(Значение, ИмяРеквизита)— обратный перевод: объект → реквизит формы.
&НаСервере
Процедура ПересчитатьДокументНаСервере()
// Реквизит "Объект" формы -> объект документа
Документ = РеквизитФормыВЗначение("Объект",
Тип("ДокументОбъект.РеализацияТоваровУслуг"));
Для Каждого Строка Из Документ.Товары Цикл
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;
// Объект -> обратно в реквизит формы
ЗначениеВРеквизитФормы(Документ, "Объект");
КонецПроцедуры
Есть и универсальная пара ДанныеФормыВЗначение() / ЗначениеВДанныеФормы() — она работает и на клиенте, и на сервере, и пригодна не только для основного реквизита, но и для отдельных частей данных формы. КопироватьДанныеФормы() копирует одну структуру данных формы в другую.
РеквизитФормыВЗначение и ЗначениеВРеквизитФормы доступны только в серверных процедурах модуля формы. Вне формы (в общем модуле, модуле объекта) их нет — там работают уже с готовыми объектами.
Почему в фоновом задании и внешнем соединении формы нет
«Серверный поток» часто понимают как фоновое задание (ФоновыеЗадания) — код, который выполняется на сервере без клиента. В таком задании формы недоступны вообще: нет ни клиента, ни контекста формы, ни пользователя, с которым можно что-то согласовать.
Тот же принцип — для внешнего соединения (COM), веб-сервисов и HTTP-сервисов. Это серверные точки входа без интерфейса, поэтому ПолучитьФорму() там не работает
, и это нормально.
// Метод общего модуля, запускаемый фоновым заданием
Процедура ПровестиПакет(МассивСсылок) Экспорт
Для Каждого Ссылка Из МассивСсылок Цикл
Объект = Ссылка.ПолучитьОбъект();
Объект.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;
// Форма здесь не нужна и недоступна — работаем с объектами напрямую
КонецПроцедуры
Вывод практический: если логику хочется вынести в фон, она не должна зависеть от формы. Вынесите расчёты в общий модуль, принимающий данные параметрами, — и его сможет вызвать и форма, и фоновое задание, и веб-сервис.
РеквизитФормыВЗначение("Объект", Тип(...)) в процедуре &НаСервере. Это даёт объект документа или справочника для обработки на сервере.ПриСозданииНаСервере: меняйте Элементы.*.Видимость, заголовки, заполняйте реквизиты. Форма доступна через ЭтотОбъект.ПолучитьФорму(...), донастройте и вызовите Открыть(). На сервере метод недоступен.ФоновыеЗадания.Типичные ошибки и как их исправить
&НаКлиенте, а на сервер отдавайте только данные. Открывать форму с сервера нельзя — это делает клиент.&НаСервереБезКонтекста — у неё нет контекста формы. Смените директиву на &НаСервере, если внутри нужен доступ к форме и её реквизитам.ПолучитьОбъект().Тип("ДокументОбъект.ИмяДокумента"), для справочника — СправочникОбъект.ИмяСправочника.Вопрос/Предупреждение в &НаКлиенте, а решение передавайте на сервер отдельным вызовом.Ещё одна частая путаница — ожидание, что данные, изменённые в клиентской процедуре, автоматически окажутся на сервере. Контекст формы передаётся на сервер при серверном вызове и возвращается после него; но &НаСервереБезКонтекста в этом обмене не участвует. Если серверная правка реквизита «не доезжает» до формы — проверьте директиву процедуры.
Частые вопросы
Можно ли вообще получить форму на сервере в 1С 8.3?
ЭтотОбъект, реквизиты и Элементы.Чем `&НаСервере` отличается от `&НаСервереБезКонтекста`?
&НаСервере выполняется с контекстом формы: есть ЭтотОбъект, Элементы, реквизиты. &НаСервереБезКонтекста контекст не передаёт — это быстрее, но форма в такой процедуре недоступна, данные принимаются только параметрами.Как на сервере получить объект документа, открытого на форме?
РеквизитФормыВЗначение("Объект", Тип("ДокументОбъект.ИмяДокумента")) в процедуре &НаСервере. Обратно изменения возвращают методом ЗначениеВРеквизитФормы.Почему форма недоступна в фоновом задании?
Можно ли из серверного кода задать вопрос пользователю?
Вопрос, Предупреждение, ПоказатьВводЗначения) работают только на клиенте. Сервер меняет данные, а взаимодействие с пользователем организуют в клиентских процедурах.