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