Как проверить наличие реквизита «Объект» у управляемой формы в 1С

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

При разработке универсального функционала в 1С:Предприятии 8 мы часто сталкиваемся с необходимостью написания кода, который должен корректно отрабатывать для самых разных типов интерфейсных окон. Типичный пример — создание общего обработчика в модуле типа МодификацияКонфигурацииПредопределяемый, выполняющего действия при открытии любой формы в системе.

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

Выясняем причину ошибки

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

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

Ниже мы подробно проанализируем различные методы решения этой задачи — от стандартных механизмов БСП до тонких приемов работы с платформенными функциями.

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

Если ваша конфигурация разработана на базе БСП (что справедливо для большинства типовых решений от 1С, таких как «Бухгалтерия предприятия», «ERP Управление предприятием», «Управление торговлей» и др.), вам не нужно изобретать велосипед. В составе БСП есть готовый, оптимизированный и надежный инструмент.

Для проверки существования реквизита достаточно вызвать функцию из стандартного общего модуля ОбщегоНазначенияКлиентСервер. Рассмотрим пример реализации:


Если ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(Форма, "Объект") Тогда
    // Реквизит гарантированно существует у формы
    Если ЗначениеЗаполнено(Форма.Объект) Тогда
        // Выполняем полезную работу с объектом
    КонецЕсли;
КонецЕсли;

Преимущества этого подхода:

  1. Универсальность контекста: функция доступна для вызова как в серверном коде, так и на стороне тонкого или веб-клиента.
  2. Высокая скорость работы: внутри БСП используются оптимизированные алгоритмы, не нагружающие систему.
  3. Чистота кода: ваш алгоритм остается лаконичным и легко читаемым для других разработчиков.

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

Этот способ был предложен в качестве финального решения в обсуждении на форуме. Метод управляемой формы ПолучитьРеквизиты() возвращает массив объектов типа РеквизитФормы, содержащих метаданные обо всех доступных реквизитах контекста формы.

Давайте разберем по шагам, как правильно обойти этот массив для решения нашей задачи:


// ВНИМАНИЕ: Метод ПолучитьРеквизиты() может быть вызван только на СЕРВЕРЕ!
РеквизитыФормы = Форма.ПолучитьРеквизиты();
ЕстьРеквизитОбъект = Ложь;

Для Каждого ТекущийРеквизит Из РеквизитыФормы Цикл
    Если ТекущийРеквизит.Имя = "Объект" Тогда
        ЕстьРеквизитОбъект = Истина;
        Прервать; // Прекращаем обход, цель достигнута
    КонецЕсли;
КонецЦикла;

Если ЕстьРеквизитОбъект Тогда
    // Теперь мы уверены, что обращение к Форма.Объект безопасно
    Если ЗначениеЗаполнено(Форма.Объект) Тогда
        // Логика обработки объекта
    КонецЕсли;
КонецЕсли;

Важные особенности метода:

Основным ограничением данного подхода является его жесткая привязка к серверному контексту. Если ваш общий модуль объявлен как клиентский (или вызывается непосредственно из клиентских процедур формы, например, ПриОткрытии или ПослеЗаписи), вызов ПолучитьРеквизиты() вызовет ошибку компиляции. Использовать данный способ целесообразно только тогда, когда вся цепочка вызовов гарантированно выполняется на сервере.

Способ 3. Универсальный метод через структуру без БСП

Что делать, если вы ведете разработку в редкой самописной конфигурации, где БСП отсутствует, а проверка должна одинаково хорошо работать и на клиенте, и на сервере? В этом случае мы можем применить оригинальный и крайне эффективный прием, основанный на поведении встроенной функции платформы ЗаполнитьЗначенияСвойств().

Давайте проанализируем пример функции-помощника:


Функция ФормаСодержитРеквизит(УправляемаяФорма, ИмяРеквизита) Экспорт
    
    // Создаем уникальный маркер, который заведомо не может быть значением реквизита формы
    МаркерОтсутствия = Новый УникальныйИдентификатор;
    
    // Инициализируем структуру, где ключом выступает имя искомого реквизита
    СтруктураПроверки = Новый Структура(ИмяРеквизита, МаркерОтсутствия);
    
    // Пытаемся скопировать данные из формы в структуру
    ЗаполнитьЗначенияСвойств(СтруктураПроверки, УправляемаяФорма);
    
    // Если значение ключа в структуре изменилось — значит, реквизит в форме существует
    Возврат СтруктураПроверки[ИмяРеквизита] <> МаркерОтсутствия;
    
КонецФункции

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

  1. Мы генерируем случайный УникальныйИдентификатор. Он служит «сторожевым» значением. Мы не можем использовать для этого Неопределено или Ложь, так как сам проверяемый реквизит формы может содержать такие значения, что привело бы к ложноотрицательному результату.
  2. Мы объявляем структуру, в которой ключ совпадает с именем проверяемого свойства формы (в нашем случае — «Объект»), и записываем туда наш уникальный маркер.
  3. Метод платформы ЗаполнитьЗначенияСвойств(Получатель, Источник) копирует значения из свойств источника в свойства получателя при совпадении их имен. Если у УправляемаяФорма есть реквизит «Объект», его текущее значение запишется в структуру, перезаписав наш маркер. Если реквизита нет — структура останется нетронутой.
  4. Мы проверяем, изменилось ли значение в структуре. Если маркер исчез, значит, реквизит на форме присутствует.

Этот способ работает невероятно быстро, не требует обращения к метаданным и полностью работоспособен в любом контексте выполнения.

Способ 4. Конструкция Попытка — Исключение

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


РеквизитСуществует = Истина;
Попытка
    // Пробуем прочитать значение реквизита
    ВременноеЗначение = Форма.Объект;
Исключение
    // Сюда мы попадем, если возникнет ошибка "Поле объекта не обнаружено"
    РеквизитСуществует = Ложь;
КонецПопытки;

Если РеквизитСуществует Тогда
    // Реквизит найден, обрабатываем данные
КонецЕсли;

Почему этот способ настоятельно не рекомендуется использовать?

Несмотря на кажущуюся простоту, данный подход имеет серьезные архитектурные и технические недостатки:

Подводим итоги

Мы рассмотрели различные варианты решения задачи. Для наглядности сопоставим их возможности в сравнительной таблице:

Метод проверки Работает на клиенте Работает на сервере Требует БСП Рекомендуется стандартами 1С
Способ 1 (Функция БСП) Да Да Да Да (Лучший выбор)
Способ 2 (ПолучитьРеквизиты) Нет Да Нет Да (В серверном коде)
Способ 3 (Через структуру) Да Да Нет Да (Для самописных баз)
Способ 4 (Попытка-Исключение) Да Да Нет Нет (Избегать использования)

Таким образом, при работе со стандартными конфигурациями всегда отдавайте предпочтение Способу 1. Если же вы создаете независимое решение «с нуля», вашим верным соратником станет гибкий и быстрый Способ 3.

← На главную