Механизм работы форм в 1С: от реквизитов до событий и серверных вызовов
Содержание
Форма в 1С — это не «картинка на экране», а пара из двух частей: данных формы (реквизиты, в которых лежат значения) и элементов (то, что видит пользователь). Элемент на экране не хранит значение сам — он показывает реквизит, с которым связан. Понять механизм формы — значит понять, как эти две части соединяются и где выполняется код: на компьютере пользователя или на сервере.
Ниже разберём устройство управляемой формы 1С 8.3 с интерфейсом «Такси»: из чего она собрана, как реквизиты привязаны к элементам и к данным объекта, в каком порядке срабатывают события и почему одна форма открывается мгновенно, а другая «думает» несколько секунд. Материал для разработчика и для администратора, который читает чужой код в конфигураторе.
Форма как связка данных и интерфейса
У любой управляемой формы есть внутренняя структура, которую видно в конфигураторе на вкладках редактора формы. Три ключевые вкладки:
- 🗂 Реквизиты — данные формы. Здесь лежат значения: число, строка, ссылка, табличная часть, а также основной реквизит, связанный с объектом.
- 🧩 Элементы — визуальная часть: поля ввода, таблицы, группы, кнопки, декорации. Элемент привязан к реквизиту через свойство
ПутьКДанным. - ⚙️ Команды — действия, которые пользователь запускает кнопкой или пунктом меню.
Главное правило: элемент сам по себе ничего не хранит. Поле ввода «Сумма» показывает реквизит формы, и когда пользователь печатает в нём число, меняется именно реквизит. Если в коде нужно прочитать введённое значение, обращаются к реквизиту, а не к элементу.
Элементы и реквизиты называют одинаково по умолчанию, из-за этого их путают. В коде Элементы.Сумма — это объект интерфейса (цвет, доступность, видимость), а просто Сумма в контексте формы — это значение реквизита.
Управляемые и обычные формы: в чём разница
В 1С 8.3 существует два вида форм, и они работают принципиально по-разному.
| Признак | Управляемая форма | Обычная форма |
|---|---|---|
| Где работает | тонкий клиент, веб-клиент, толстый клиент | только толстый клиент |
| Вёрстка | автоматическая, по группам и потоку | ручная, по пикселям |
| Код | делится на клиент и сервер | весь код на клиенте |
| Разработка новых | да, это основной вариант | нет, только поддержка старых баз |
Управляемые формы появились в платформе 8.2 и стали основным механизмом интерфейса. В типовых конфигурациях (БП 3.0, ЗУП 3.1, УТ 11) все формы управляемые. Обычные формы остались для совместимости со старыми решениями и в режиме обычного приложения не делятся на клиент и сервер — поэтому старый код из обычной формы нельзя просто перенести в управляемую.
Если вы открываете конфигурацию и видите в свойствах формы разделение процедур на &НаКлиенте и &НаСервере — перед вами управляемая форма. Если такого разделения нет — обычная.
Реквизиты, элементы и команды: как собрана форма
Разберём три составные части подробнее — именно их настраивает разработчик.
Реквизиты формы — это переменные уровня формы. У каждой формы есть один основной реквизит (у формы документа это сам документ, у формы справочника — элемент). Основной реквизит связывает форму с данными объекта информационной базы. Остальные реквизиты — вспомогательные: флажки, отборы, временные значения, которые живут только пока форма открыта.
Элементы формы строятся деревом. Группы (ОбычнаяГруппа, страницы, командная панель) задают расположение, а вложенные поля показывают реквизиты. Платформа сама расставляет элементы по потоку — разработчик управляет группировкой, а не координатами. Каждое поле ссылается на реквизит через ПутьКДанным; разорвите эту связь — поле перестанет показывать и принимать данные.
Команды — это действия. Команда ссылается на процедуру-обработчик, а на форму выводится кнопкой или пунктом меню. Команды бывают стандартные (платформа добавляет «Записать», «Провести») и собственные, которые пишет разработчик.
Как форма работает с данными объекта
Здесь кроется механизм, который чаще всего понимают неправильно. Данные формы — это копия данных объекта, а не сам объект.
Когда открывается форма документа, платформа читает документ из базы и раскладывает его реквизиты в реквизиты формы. Пользователь правит копию в форме. Только при записи платформа собирает данные формы обратно в объект и пишет его в базу.
Поэтому в коде формы прямого объекта нет — есть данные формы. Чтобы получить настоящий объект (например, вызвать его метод), применяют преобразование:
&НаСервере
Процедура ПересчитатьНаСервере()
Документ = РеквизитФормыВЗначение("Объект"); // данные формы -> объект
Документ.Пересчитать(); // метод объекта
ЗначениеВРеквизитФормы(Документ, "Объект"); // объект -> данные формы
КонецПроцедуры
РеквизитФормыВЗначениесобирает объект из данных формы.ЗначениеВРеквизитФормыраскладывает изменённый объект обратно.
Эти преобразования недёшевы: платформа копирует все данные, включая табличные части. В цикле их не вызывают — иначе форма «повиснет». Для простого чтения отдельного значения достаточно обратиться к реквизиту напрямую, преобразование не нужно.
Табличные части формы работают так же: в форме лежит таблица значений, связанная с табличной частью объекта. Строки добавляют и правят в данных формы, а в базу они попадают только при записи документа.
У такой копии есть практическое следствие. Пока пользователь не нажал «Записать», все его правки существуют только в открытой форме. Если сеанс оборвётся или форма закроется без записи — изменения пропадут, в базе останется прежняя версия. Поэтому проведение, расчёт итогов и любые действия, которые должны сохраниться, выполняют либо при записи, либо явной командой, которая пишет объект в базу.
Ещё одно следствие — две открытые формы одного документа работают с разными копиями. Один пользователь записал изменения, второй у себя их не видит, пока не перечитает. Платформа предупредит о конфликте при попытке записать устаревшую версию — это не ошибка формы, а защита от потери чужих правок.
Клиент и сервер: где выполняется код формы
Управляемая форма исполняется в двух местах сразу. Часть кода работает на компьютере пользователя (клиент), часть — на сервере. Разделение задаётся директивами компиляции над процедурой.
&НаКлиенте— выполняется у пользователя. Отсюда управляют интерфейсом, показывают вопросы, открывают другие формы. Прямого доступа к базе данных здесь нет.&НаСервере— выполняется на сервере, имеет доступ к базе и к данным формы. При вызове платформа передаёт данные формы на сервер и возвращает обратно.&НаСервереБезКонтекста— тоже на сервере, но данные формы не передаются. Такой вызов легче: меньше трафика между клиентом и сервером.&НаКлиентеНаСервереБезКонтекста— общая процедура, доступная и там, и там, без контекста формы.
Каждый переход с клиента на сервер — это сетевой вызов. Чем их меньше, тем быстрее форма. Запрос к базе, чтение справочника, проведение документа — всё это может идти только на сервере. Реакция на действие пользователя (нажал кнопку, изменил поле) начинается на клиенте, а за данными уходит на сервер.
Стоимость вызова зависит не только от его количества, но и от объёма передаваемых данных. Вызов &НаСервере тянет с клиента на сервер и обратно всю копию формы вместе с табличными частями. Если в форме крупная таблица, такой round-trip ощутимо дороже, чем вызов &НаСервереБезКонтекста, который передаёт только параметры процедуры. Поэтому при одинаковой задаче без контекста работает быстрее.
Логика распределения простая. На клиенте остаётся то, что управляет интерфейсом и реагирует на пользователя: показать вопрос, открыть другую форму, сменить видимость поля. На сервер уходит всё, что касается базы и бизнес-логики. А промежуточный слой — общие модули — позволяет вынести повторяющийся серверный код из формы, чтобы он не дублировался в десятках обработок.
Правило простое: что можно сделать без базы — делайте на клиенте; что требует базу — на сервере, и собирайте такие операции в один вызов, а не в несколько.
События формы: что срабатывает и в каком порядке
Форма живёт по событиям. Платформа вызывает обработчики в предсказуемом порядке — зная его, вы понимаете, куда поставить свой код.
Основные события при открытии формы документа идут так:
ПриЧтенииНаСервере— объект прочитан из базы (для существующего документа).ПриСозданииНаСервере— форма создаётся на сервере; здесь настраивают видимость, отборы, начальные значения. Выполняется один раз.ПриОткрытии— форма открывается на клиенте; здесь клиентская донастройка.
При записи порядок другой:
ПередЗаписью(клиент) — можно отменить запись, спросить подтверждение.ПередЗаписьюНаСервере— последняя проверка перед записью.ПриЗаписиНаСервере— объект уже пишется в транзакции.ПослеЗаписи(клиент) — обновить интерфейс после успешной записи.
При закрытии срабатывают ПередЗакрытием (можно удержать форму открытой) и ПриЗакрытии.
Отдельно работают события элементов: ПриИзменении поля, ПриАктивизацииСтроки таблицы, Выбор, Открытие. Они клиентские — пользователь что-то сделал, код реагирует. Если реакции нужны данные из базы, обработчик вызывает серверную процедуру.
Распространённая ошибка — тяжёлые вычисления в ПриСозданииНаСервере. Это событие выполняется до показа формы, и всё, что в нём медленное, задерживает открытие. Вынесите то, что не нужно сразу, в отдельную команду или в фоновое задание.
Как ускорить медленную форму
Если форма открывается долго или «подтормаживает» при вводе, причина почти всегда в лишних серверных вызовах или в тяжёлой загрузке данных. Что проверить:
- 🔁 Вызовы сервера в цикле. Серверную процедуру вызвали внутри обхода строк таблицы — каждый проход уходит на сервер и обратно. Соберите данные за один вызов и верните массивом.
- 📦 Лишний контекст. Если серверной процедуре не нужны данные формы, поставьте
&НаСервереБезКонтекста. Платформа не будет гонять копию формы туда-сюда. - 🧮 Вычисления в событии открытия. Всё, что можно посчитать позже или по запросу пользователя, убирают из
ПриСозданииНаСервере. - 🎨 Оформление кодом вместо условного оформления. Подсветку строк, доступность полей по условию лучше задавать условным оформлением формы, а не пробегать по строкам кодом при каждом изменении.
- 🗃 Чтение больших таблиц целиком. Не загружайте в форму тысячи строк, если пользователь видит десяток. Применяйте динамический список с отбором — он читает данные порциями.
Динамический список — отдельный механизм: это не копия данных в форме, а «окно» в базу, которое платформа подгружает по мере прокрутки. Для списков документов и справочников он на порядок экономнее, чем загрузка таблицы значений вручную.
Частые ошибки при работе с формами
Эти ошибки встречаются в чужом коде чаще всего — проверьте их, прежде чем искать что-то сложное.
- Обращение к базе на клиенте. Запрос, чтение справочника или проведение в
&НаКлиентевызовут ошибку компиляции. Такой код переносят на сервер. - Правка объекта, а не данных формы. Вызвали метод объекта, но забыли вернуть результат через
ЗначениеВРеквизитФормы— изменения не попадут ни на экран, ни в базу. - Путаница элемента и реквизита. Присвоили значение
Элементы.Поле, ожидая изменить данные. Нужно менять реквизит, на который поле ссылается; через элемент управляют только видом (цвет, доступность, видимость). - Тяжёлый
ПриСозданииНаСервере. Форма открывается с задержкой, потому что в событии создания идёт долгий запрос или перебор.
Ни одно из этого не чинится «перезапуском 1С» — это ошибки логики кода, и правят их в конфигураторе.
Частые вопросы
Чем реквизит формы отличается от реквизита объекта?
Почему нельзя обратиться к базе данных прямо на клиенте?
&НаСервере.Когда ставить `&НаСервереБезКонтекста` вместо `&НаСервере`?
Можно ли перенести код из обычной формы в управляемую без переделки?
Как получить настоящий объект документа в коде формы?
РеквизитФормыВЗначение("Объект") на сервере — платформа соберёт объект из данных формы. После изменения вернуть обратно через ЗначениеВРеквизитФормы. Для чтения одного значения преобразование не требуется — достаточно обратиться к реквизиту формы.