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