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