Работа с формой объекта в серверном коде 1С 8.3

· 9 мин

Содержание

Получить управляемую форму как самостоятельный объект на сервере в 1С:Предприятие 8.3 нельзя — метод ПолучитьФорму() выполняется только на клиенте. На сервере вы работаете не с «формой целиком», а с её контекстом: внутри серверных процедур самой формы к ней обращаются через ЭтотОбъект, реквизиты превращают в прикладные объекты через РеквизитФормыВЗначение(), а события ловят в процедурах с директивой &НаСервере.

Это ограничение архитектурное, а не ошибка. Разделение на клиент и сервер в управляемом приложении устроено так, что визуальная форма живёт на клиенте, а сервер оперирует данными. Поэтому вопрос «как получить форму на сервере» на практике распадается на несколько разных задач, и для каждой есть свой приём.

Ниже — где метод ПолучитьФорму работает, что именно доступно в серверном коде формы, как передать и прочитать параметры, как обрабатывать серверные события и почему в фоновом задании форму взять в принципе невозможно.

Почему управляемую форму нельзя взять на сервере как объект

В управляемом приложении клиент и сервер физически разделены. Форма — это элемент интерфейса: кнопки, поля, таблицы, события ввода. Всё это отображается и реагирует на действия пользователя на клиенте (тонком, веб- или толстом). Сервер интерфейс не рисует и мышь не слушает — он выполняет запросы, читает и пишет данные, проверяет права.

Из-за этого объект УправляемаяФорма существует на стороне клиента. Сервер «видит» форму только в один момент: когда с клиента вызывается серверная процедура этой же формы. На время такого вызова платформа передаёт на сервер контекст формы — её реквизиты и настройки элементов, — а после возврата отправляет изменения обратно на клиент.

Отсюда вытекает главное правило: получить произвольную «чужую» форму на сервере невозможно. Доступна только та форма, из серверной процедуры которой вы сейчас находитесь.

Монопольный доступ и прочие тонкости платформы здесь ни при чём — ограничение чисто архитектурное и действует всегда, независимо от режима запуска.

Что доступно внутри серверных процедур формы

Когда вы пишете процедуру с директивой &НаСервере в модуле формы, у вас есть доступ к самой форме и её содержимому.

  • 🔹 ЭтотОбъект — ссылка на текущую управляемую форму. В модуле формы это и есть «форма» в серверном коде.
  • 🔹 Элементы — коллекция элементов (поля, группы, таблицы, кнопки). На сервере можно менять их свойства: Видимость, Доступность, ТолькоПросмотр, заголовки.
  • 🔹 Реквизиты формы — обращение по имени напрямую, например Объект, СписокТоваров, ваши служебные реквизиты.
  • 🔹 Параметры — параметры, с которыми форму открыли (надёжно доступны в момент создания формы).

Пример процедуры создания формы, которая настраивает её на сервере:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    // ЭтотОбъект — сама управляемая форма
    ЭтотОбъект.Заголовок = "Карточка: " + Строка(Параметры.Ключ);

    // Управляем элементами прямо на сервере
    Элементы.Комментарий.Видимость = Ложь;
    Элементы.СуммаДокумента.ТолькоПросмотр = Истина;

КонецПроцедуры

Важная оговорка про директивы. Доступ к форме есть только у процедур &НаСервере — они выполняются с контекстом формы. Процедуры &НаСервереБезКонтекста работают без контекста формы: в них нет ни ЭтотОбъект, ни Элементы, ни реквизитов. Это сделано ради производительности: такой вызов не гоняет контекст формы на сервер и обратно. Если вам внутри нужен доступ к форме — директива должна быть именно &НаСервере.

&НаСервереБезКонтекста быстрее, но «не видит» форму. Не пытайтесь обращаться там к ЭтотОбъект — получите ошибку, что переменная не определена.

Отдельно про управляемые и обычные формы. Всё сказанное выше — про управляемые формы 1С:Предприятие 8.3, которые разделены на клиент и сервер. Обычные формы (наследие версий 8.1–8.2, режим обычного приложения) устроены иначе: там форма — единый объект без строгого деления на контексты, и код выполняется в общем пространстве. Если конфигурация работает в режиме управляемого приложения — а это все современные типовые решения, — вас касается именно управляемая модель. Переносить на неё приёмы обычных форм (прямое обращение к форме из любого места) нельзя: в управляемом приложении это не скомпилируется.

Ещё один нюанс управляемых форм: изменения элементов, сделанные на сервере, доходят до пользователя не сразу, а после возврата управления на клиент. Поэтому настройку внешнего вида (видимость, доступность, заголовки) делают разом в серверной процедуре, а не «по кусочкам» в середине длинного расчёта — всё равно клиент увидит только итоговое состояние.

Метод ПолучитьФорму: клиентский вызов и его параметры

Сам метод ПолучитьФорму() возвращает объект формы, но вызывается он на клиенте. Его назначение — получить форму, не открывая её сразу, чтобы предварительно что-то в ней настроить, а потом вызвать Открыть().

&НаКлиенте
Процедура ОткрытьКарточкуЗаказа(СсылкаНаЗаказ)

    Форма = ПолучитьФорму("Документ.ЗаказПокупателя.ФормаОбъекта",
        Новый Структура("Ключ", СсылкаНаЗаказ));

    // при необходимости настраиваем форму до показа
    Форма.Открыть();

КонецПроцедуры

Основные параметры метода:

ПараметрНазначение
Имя формыПолное имя: Документ.ИмяДокумента.ФормаОбъекта
ПараметрыСтруктура параметров открытия (Ключ, Отбор и др.)
ВладелецФорма-владелец (для связи и уникальности)
УникальностьКлюч уникальности окна
ОкноВ каком окне показывать

Если вам нужно просто открыть форму, обычно удобнее ОткрытьФорму() — он сразу и получает, и показывает. ПолучитьФорму() берут тогда, когда между получением и открытием нужно выполнить дополнительные действия.

Оба метода — ПолучитьФорму и ОткрытьФорму — клиентские. В серверной процедуре конфигуратор подчеркнёт их вызов и сообщит, что метод в этом контексте недоступен.

Как передать параметры и прочитать контекст формы на сервере

Чтобы форма «знала», с каким объектом её открыли, при открытии ей передают структуру параметров. Стандартный параметр для формы объекта — Ключ (ссылка на элемент или документ). Есть и другие: ЗначениеКопирования, Основание, Отбор, ПараметрКоманды.

На сервере эти значения читают из коллекции Параметры в обработчике ПриСозданииНаСервере:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Если Параметры.Свойство("Основание")
        И ЗначениеЗаполнено(Параметры.Основание) Тогда
        ЗаполнитьПоОснованию(Параметры.Основание);
    КонецЕсли;

КонецПроцедуры

Коллекцию Параметры надёжно читать именно в момент создания формы. После того как форма создана, обращаться к ней как к источнику данных не стоит — используйте для хранения собственные реквизиты формы.

Если нужно передать на сервер не весь контекст, а отдельные значения (ради скорости), их отправляют аргументами в процедуру &НаСервереБезКонтекста. Так делают для тяжёлых операций, которым форма целиком не нужна.

На практике выбор такой: нужна вся форма с реквизитами и элементами — берите &НаСервере; нужен только расчёт по нескольким входным значениям — выносите его в &НаСервереБезКонтекста и передавайте аргументы явно. Второй вариант не гоняет лишние данные между клиентом и сервером и заметно экономит трафик на нагруженных формах с большими табличными частями.

Серверные обработчики событий формы

«Обработка событий формы в серверном потоке» — это стандартные серверные обработчики, которые платформа вызывает в определённые моменты жизни формы. У каждого есть версия НаСервере.

  1. ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) — форма создаётся. Здесь настраивают элементы, читают параметры, заполняют реквизиты.
  2. ПриЧтенииНаСервере(ТекущийОбъект) — объект прочитан из базы. Удобно донастроить форму под прочитанные данные.
  3. ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) — перед записью объекта.
  4. ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи) — в момент записи, внутри транзакции.
  5. ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи) — после записи.
  6. ОбработкаПроверкиЗаполненияНаСервере(Отказ, ПроверяемыеРеквизиты) — серверная проверка заполнения.
&НаСервере
Процедура ПриЧтенииНаСервереПослеЧтения(ТекущийОбъект)
    // донастраиваем форму под уже прочитанный объект
    Элементы.ПричинаАннулирования.Видимость =
        (ТекущийОбъект.Состояние = Перечисления.Состояния.Аннулирован);
КонецПроцедуры

Ключевое отличие от клиентских событий: серверные обработчики не умеют общаться с пользователем. Нельзя показать Вопрос() или Предупреждение(), нельзя ждать ответа. Диалоги и реакция на ввод — только в клиентских процедурах &НаКлиенте. Сервер меняет данные и настройки, клиент — разговаривает с пользователем.

Преобразование реквизитов формы в объект и обратно

Частая настоящая задача за формулировкой «получить форму на сервере» звучит иначе: получить на сервере не форму, а прикладной объект, который на форме редактируется. Данные формы хранятся в особой структуре (данные формы), и напрямую как объект их не использовать. Для перевода есть пара методов, доступных в &НаСервере:

  • РеквизитФормыВЗначение(ИмяРеквизита, Тип) — превращает реквизит формы в прикладной объект (документ, элемент справочника).
  • ЗначениеВРеквизитФормы(Значение, ИмяРеквизита) — обратный перевод: объект → реквизит формы.
&НаСервере
Процедура ПересчитатьДокументНаСервере()

    // Реквизит "Объект" формы -> объект документа
    Документ = РеквизитФормыВЗначение("Объект",
        Тип("ДокументОбъект.РеализацияТоваровУслуг"));

    Для Каждого Строка Из Документ.Товары Цикл
        Строка.Сумма = Строка.Количество * Строка.Цена;
    КонецЦикла;

    // Объект -> обратно в реквизит формы
    ЗначениеВРеквизитФормы(Документ, "Объект");

КонецПроцедуры

Есть и универсальная пара ДанныеФормыВЗначение() / ЗначениеВДанныеФормы() — она работает и на клиенте, и на сервере, и пригодна не только для основного реквизита, но и для отдельных частей данных формы. КопироватьДанныеФормы() копирует одну структуру данных формы в другую.

РеквизитФормыВЗначение и ЗначениеВРеквизитФормы доступны только в серверных процедурах модуля формы. Вне формы (в общем модуле, модуле объекта) их нет — там работают уже с готовыми объектами.

Почему в фоновом задании и внешнем соединении формы нет

«Серверный поток» часто понимают как фоновое задание (ФоновыеЗадания) — код, который выполняется на сервере без клиента. В таком задании формы недоступны вообще: нет ни клиента, ни контекста формы, ни пользователя, с которым можно что-то согласовать.

Тот же принцип — для внешнего соединения (COM), веб-сервисов и HTTP-сервисов. Это серверные точки входа без интерфейса, поэтому ПолучитьФорму() там не работает , и это нормально.

// Метод общего модуля, запускаемый фоновым заданием
Процедура ПровестиПакет(МассивСсылок) Экспорт

    Для Каждого Ссылка Из МассивСсылок Цикл
        Объект = Ссылка.ПолучитьОбъект();
        Объект.Записать(РежимЗаписиДокумента.Проведение);
    КонецЦикла;
    // Форма здесь не нужна и недоступна — работаем с объектами напрямую

КонецПроцедуры

Вывод практический: если логику хочется вынести в фон, она не должна зависеть от формы. Вынесите расчёты в общий модуль, принимающий данные параметрами, — и его сможет вызвать и форма, и фоновое задание, и веб-сервис.

Что именно вам нужно сделать «на сервере»?

Типичные ошибки и как их исправить

Диагностика: выберите симптом

Ещё одна частая путаница — ожидание, что данные, изменённые в клиентской процедуре, автоматически окажутся на сервере. Контекст формы передаётся на сервер при серверном вызове и возвращается после него; но &НаСервереБезКонтекста в этом обмене не участвует. Если серверная правка реквизита «не доезжает» до формы — проверьте директиву процедуры.

Частые вопросы

Можно ли вообще получить форму на сервере в 1С 8.3?
Нет. Объект управляемой формы существует на клиенте. На сервере доступен только контекст текущей формы внутри её серверных процедур — через ЭтотОбъект, реквизиты и Элементы.
Чем `&НаСервере` отличается от `&НаСервереБезКонтекста`?
&НаСервере выполняется с контекстом формы: есть ЭтотОбъект, Элементы, реквизиты. &НаСервереБезКонтекста контекст не передаёт — это быстрее, но форма в такой процедуре недоступна, данные принимаются только параметрами.
Как на сервере получить объект документа, открытого на форме?
Через РеквизитФормыВЗначение("Объект", Тип("ДокументОбъект.ИмяДокумента")) в процедуре &НаСервере. Обратно изменения возвращают методом ЗначениеВРеквизитФормы.
Почему форма недоступна в фоновом задании?
Фоновое задание выполняется на сервере без клиента и без интерфейса. Формы — часть клиентского интерфейса, поэтому их там нет. Логику, которую нужно гонять в фоне, выносят в общий модуль, не зависящий от формы.
Можно ли из серверного кода задать вопрос пользователю?
Нет. Диалоги (Вопрос, Предупреждение, ПоказатьВводЗначения) работают только на клиенте. Сервер меняет данные, а взаимодействие с пользователем организуют в клиентских процедурах.