Почему возникает ошибка «Значение не является значением объектного типа (Получить)» в форме производственного календаря?

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

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

Анализ проблемы и симптомов ошибки

Исключение возникает непосредственно во время отрисовки интерфейсного элемента календаря в процедуре-обработчике КалендарьПриВыводеПериода:


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

Платформа выдает ошибку: «Значение не является значением объектного типа (Получить)». Это означает, что метод Получить() вызывается у переменной или свойства, которое в текущий момент содержит значение простого типа, чаще всего Неопределено или Null.

В строке с вычислением цвета выполняются два последовательных вызова:

  1. Внутренний вызов: ВидыДней.Получить(СтрокаОформленияПериода.Дата).
  2. Внешний вызов: ЦветаВидовДней.Получить(...).

Если хотя бы один из объектов — ВидыДней или ЦветаВидовДней — не инициализирован как коллекция (например, Соответствие или ФиксированноеСоответствие), выполнение кода прерывается с ошибкой.

Выясняем причину через отладку

Поставим точку останова на строке с вызовом метода Получить() и проанализируем значения контекстных переменных в табло. Как показывает практика, реквизит ВидыДней на клиенте равен Неопределено, в то время как в оригинальной конфигурации он содержит объект типа ФиксированноеСоответствие.

Выясним причину, почему это происходит:

  1. Неполный перенос метаданных: Справочник ПроизводственныеКалендари тесно завязан на регистр сведений ДанныеПроизводственногоКалендаря, перечисление ВидыДнейПроизводственногоКалендаря и общий модуль КалендарныеГрафики. Если справочник скопирован отдельно, серверная процедура чтения данных из регистра либо падает, либо не выполняется, оставляя реквизит пустым.
  2. Потеря типа реквизита управляемой формы: При копировании формы между конфигурациями реквизиты с произвольным типом могут сбрасывать свои настройки, и при открытии формы им по умолчанию присваивается Неопределено.
  3. Ограничения клиент-серверной передачи: Коллекция Соответствие не сериализуется при передаче между клиентом и сервером в управляемой форме. На сервере обязательно должен создаваться неизменяемый аналог — ФиксированноеСоответствие.
  4. Специфика события «ПриВыводеПериода»: Это событие элемента ПолеКалендаря вызывается платформой автоматически при любой перерисовке, смене масштаба или отображении окна, иногда еще до полного завершения серверных процедур наполнения данных.

Способ 1. Гарантированная инициализация коллекций на сервере

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

Посмотрим на пример корректного заполнения реквизита на сервере:


&НаСервере
Процедура ИнициализироватьКоллекцииФормы()
    
    // Создаем временное соответствие для заполнения
    ВременныеВидыДней = Новый Соответствие;
    
    // Здесь выполняется запрос к регистру сведений ДанныеПроизводственногоКалендаря
    // Если записей нет, коллекция остается пустой
    
    // Обязательно преобразуем в ФиксированноеСоответствие для передачи на клиент
    ВидыДней = Новый ФиксированноеСоответствие(ВременныеВидыДней);
    
    Если ЦветаВидовДней = Неопределено Тогда
        ЦветаВидовДней = Новый ФиксированноеСоответствие(Новый Соответствие);
    КонецЕсли;
    
КонецПроцедуры

Способ 2. Защитная проверка (Guard Clause) перед выводом оформления

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


&НаКлиенте
Процедура КалендарьПриВыводеПериода(Элемент, ОформлениеПериода)
    
    // Если коллекции еще не инициализированы на сервере, прерываем отрисовку
    Если ВидыДней = Неопределено Или ЦветаВидовДней = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Для Каждого СтрокаОформленияПериода Из ОформлениеПериода.Даты Цикл
        ВидДня = ВидыДней.Получить(СтрокаОформленияПериода.Дата);
        
        ЦветОформленияДня = Неопределено;
        Если ВидДня <> Неопределено Тогда
            ЦветОформленияДня = ЦветаВидовДней.Получить(ВидДня);
        КонецЕсли;
        
        Если ЦветОформленияДня = Неопределено Тогда
            ЦветОформленияДня = ОбщегоНазначенияКлиент.ЦветСтиля("ВидДняПроизводственногоКалендаряНеУказанЦвет");
        КонецЕсли;
        
        СтрокаОформленияПериода.ЦветТекста = ЦветОформленияДня;
    КонецЦикла;
    
КонецПроцедуры

Способ 3. Проверка состава перенесенных метаданных

Разберем по шагам, какие связанные объекты конфигурации необходимо перенести из базы-донора для штатной работы функционала производственного календаря:

  1. Регистр сведений: ДанныеПроизводственногоКалендаря — именно в нем хранятся даты и соответствующие им значения перечисления.
  2. Перечисление: ВидыДнейПроизводственногоКалендаря (со значениями: Рабочий, Суббота, Воскресенье, Праздник, Предпраздничный).
  3. Элементы стиля: ВидДняПроизводственногоКалендаряНеУказанЦвет, а также цвета для каждого вида дня (например, субботы, воскресенья, праздничных дней).
  4. Общие модули: Модуль КалендарныеГрафики или соответствующие процедуры БСП, считывающие данные производственного календаря.

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

← На главную