Как устранить ошибку «Поле объекта не обнаружено» при создании документа из модуля формы

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки в среде «1С:Предприятие» программисты нередко сталкиваются с ситуациями, когда стандартный, многократно проверенный код внезапно отказывается работать в контексте конкретной формы. Одной из таких коварных проблем является ошибка «Поле объекта не обнаружено» при попытке обратиться к глобальным коллекциям метаданных, например, к менеджеру документов через конструкцию Документы.ИмяДокумента.СоздатьДокумент().

В этой статье мы подробно разберем, почему возникает эта ошибка, как работает механизм разрешения имен в платформе «1С:Предприятие», и рассмотрим несколько эффективных способов решения данной проблемы.

Суть проблемы и симптомы

Давайте представим стандартную задачу: у нас есть внешняя или встроенная обработка. Внутри нее создано несколько форм. Из основной формы мы открываем вспомогательную форму (например, «ФормаЭлемента») и передаем в нее некоторые параметры. На этой вспомогательной форме мы создаем кнопку, по нажатию на которую должен программно создаваться новый документ (например, «Платежное поручение»).

Мы пишем стандартный код для создания документа на сервере:


&НаСервере
Процедура СоздатьПротоколНаСервере()
    ДокПриход = Документы.ПлатежноеПоручение.СоздатьДокумент();
    // Дальнейшее заполнение и запись документа
КонецПроцедуры

&НаКлиенте
Процедура СоздатьПротокол(Команда)
    СоздатьПротоколНаСервере();
КонецПроцедуры

Однако при выполнении этого кода платформа выдает ошибку:

{Обработка.МояОбработка.Форма.ФормаЭлемента.Форма(X)}: Поле объекта не обнаружено (ПлатежноеПоручение)

При этом, если мы перенесем точно такой же код в другую форму (например, «Форма3») той же самой обработки, создание документа пройдет абсолютно гладко и без ошибок. Давайте проанализируем ситуацию и выясним истинную причину такого поведения системы.

Почему возникает конфликт имен? Разбираем контекст управляемой формы

Причина такого странного поведения кроется в конфликте (перекрытии) локального и глобального контекстов управляемой формы. В платформе 1С существует строгий порядок разрешения имен при обращении к свойствам и методам в модуле формы. Когда система встречает идентификатор (в нашем случае Документы), она ищет его «изнутри наружу» по следующей цепочке приоритетов:

  1. Локальные переменные и параметры выполняемой процедуры или функции.
  2. Переменные, объявленные в разделе Перем в самом верху модуля формы.
  3. Реквизиты управляемой формы.
  4. Свойства и методы самого программного объекта формы (УправляемаяФорма).
  5. Свойства и методы основного реквизита формы (если это объектный тип, например, справочник или документ).
  6. Глобальный контекст платформы (системные функции, глобальные переменные, общие модули и менеджеры коллекций метаданных, такие как Справочники, Документы, РегистрыСведений).

Если на нашей проблемной форме («ФормаЭлемента») разработчик создал собственный реквизит формы (например, таблицу значений, дерево или динамический список) и назвал его «Документы», то приоритет поиска этого имени смещается на шаг 3.

В результате платформа перестает видеть глобальный менеджер метаданных Документы. Вместо этого под идентификатором Документы она начинает понимать конкретный локальный реквизит текущей управляемой формы. Разумеется, у локального реквизита (будь то таблица или список) нет свойства ПлатежноеПоручение, что и приводит к закономерной ошибке: «Поле объекта не обнаружено».

Как диагностировать проблему с помощью отладчика

Давайте убедимся в этом предположении на практике с помощью отладочных инструментов. Для этого выполним несколько простых шагов:

  1. Откроем модуль проблемной управляемой формы в конфигураторе.
  2. Найдем процедуру ПриСозданииНаСервере (или создадим ее, если она отсутствует).
  3. Установим точку останова на первой строке этой процедуры.
  4. Запустим сеанс в режиме отладки и откроем нашу форму.
  5. В момент остановки системы откроем окно вычисления выражений (сочетание клавиш Shift + F9).
  6. Введем в поле выражение слово Документы и нажмем клавишу ввода.

Если в окне результатов вместо ожидаемого типа ДокументыМенеджер мы увидим, например, тип ДанныеФормыКоллекция, ДинамическийСписок или ТаблицаЗначений, это будет стопроцентным подтверждением нашей гипотезы: имя глобального контекста перекрыто локальным реквизитом.

Способы решения проблемы

В зависимости от архитектуры вашей конфигурации и степени интеграции реквизита формы в логику программы, мы можем применить один из трех вариантов решения.

Способ 1. Рефакторинг и переименование локального реквизита (Рекомендуемый метод)

Самым правильным и надежным решением является устранение самого конфликта имен. Использование имен глобального контекста для локальных переменных и реквизитов считается плохим стилем программирования.

Выполним переименование:

  1. Откроем редактор управляемой формы в конфигураторе.
  2. Перейдем на вкладку Реквизиты (в правой части экрана).
  3. Найдем реквизит с именем Документы.
  4. Переименуем его в более понятное и безопасное имя, отражающее его суть. Например: ТаблицаДокументов, СписокДокументов или ДокументыДляОбработки.
  5. Нажмем сочетание клавиш Ctrl + Shift + F (Глобальный поиск) и заменим все упоминания старого имени Документы на новое имя в пределах модуля этой формы.

После этого платформа снова начнет успешно разрешать имя Документы как глобальную коллекцию менеджеров документов, и ошибка исчезнет.

Способ 2. Вынос логики создания документа в общий модуль

Бывают ситуации, когда реквизит формы Документы задействован во множестве сложных связей, используется в динамических списках на нескольких страницах формы, связан с элементами интерфейса, и его переименование может повлечь за собой длительное тестирование и риски что-то сломать. В таком случае мы можем обойти ограничение контекста формы.

Для этого мы можем перенести процедуру создания документа в общий серверный модуль, где локальный контекст формы отсутствует по определению. Выполним следующие действия:

  1. Найдем или создадим общий модуль с включенными свойствами Сервер и Вызов сервера (например, с именем ДокументыСервер).
  2. Определим в нем экспортную функцию для создания нашего документа:

// В общем модуле "ДокументыСервер"
Функция СоздатьПлатежноеПоручениеНаСервере(ДанныеЗаполнения) Экспорт
    
    НовыйДокумент = Документы.ПлатежноеПоручение.СоздатьДокумент();
    // Заполняем реквизиты из переданной структуры ДанныеЗаполнения
    НовыйДокумент.Сотрудник = ДанныеЗаполнения.Сотрудник;
    НовыйДокумент.Отдел     = ДанныеЗаполнения.Отдел;
    
    НовыйДокумент.Записать();
    
    Возврат НовыйДокумент.Ссылка;
    
КонецФункции
  1. Теперь в модуле нашей проблемной формы мы можем безопасно вызвать этот общий модуль, передав туда необходимые параметры:

&НаСервере
Процедура СоздатьПротоколНаСервере()
    
    ДанныеЗаполнения = Новый Структура;
    ДанныеЗаполнения.Вставить("Сотрудник", Объект.Сотрудник);
    ДанныеЗаполнения.Вставить("Отдел", Объект.Отдел);
    
    // Вызываем метод общего модуля, где контекст формы не мешает работе
    СсылкаНаНовыйДокумент = ДокументыСервер.СоздатьПлатежноеПоручениеНаСервере(ДанныеЗаполнения);
    
КонецПроцедуры

Способ 3. Использование модуля менеджера обработки

Если мы не хотим создавать новые общие модули в конфигурации, мы можем задействовать модуль менеджера нашей собственной обработки. Это также отличная изолированная область выполнения кода, не привязанная к контексту конкретной формы.

Разберем этот вариант по шагам:

  1. Откроем модуль менеджера обработки МояОбработка.
  2. Напишем там экспортную процедуру создания документа:

// В модуле менеджера обработки "МояОбработка"
Процедура СоздатьПлатежку(ПараметрыЗаполнения) Экспорт
    
    НовыйДок = Документы.ПлатежноеПоручение.СоздатьДокумент();
    ЗаполнитьЗначенияСвойств(НовыйДок, ПараметрыЗаполнения);
    НовыйДок.Записать();
    
КонецПроцедуры
  1. В модуле управляемой формы вызовем этот метод через менеджер обработки:

&НаСервере
Процедура СоздатьПротоколНаСервере()
    
    ПараметрыЗаполнения = Новый Структура("Сотрудник, Отдел", Сотрудник, Отдел);
    // Обращаемся напрямую к менеджеру нашей обработки
    Обработки.МояОбработка.СоздатьПлатежку(ПараметрыЗаполнения);
    
КонецПроцедуры

Резюме и правила хорошего тона в разработке 1С

Для того чтобы избежать подобных неочевидных ошибок в будущем, мы рекомендуем придерживаться простых стандартов кодирования на платформе «1С:Предприятие»:

← На главную