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