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