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