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