При переносе объектов или доработке типовой функциональности подсистемы производственных календарей разработчики нередко сталкиваются с падением формы при открытии или перерисовке календаря. Рассмотрим типичную ситуацию, разберем причины возникновения исключения и пошагово устраним неполадку.
Исключение возникает непосредственно во время отрисовки интерфейсного элемента календаря в процедуре-обработчике КалендарьПриВыводеПериода:
&НаКлиенте
Процедура КалендарьПриВыводеПериода(Элемент, ОформлениеПериода)
Для Каждого СтрокаОформленияПериода Из ОформлениеПериода.Даты Цикл
ЦветОформленияДня = ЦветаВидовДней.Получить(ВидыДней.Получить(СтрокаОформленияПериода.Дата));
Если ЦветОформленияДня = Неопределено Тогда
ЦветОформленияДня = ОбщегоНазначенияКлиент.ЦветСтиля("ВидДняПроизводственногоКалендаряНеУказанЦвет");
КонецЕсли;
СтрокаОформленияПериода.ЦветТекста = ЦветОформленияДня;
КонецЦикла;
КонецПроцедуры
Платформа выдает ошибку: «Значение не является значением объектного типа (Получить)». Это означает, что метод Получить() вызывается у переменной или свойства, которое в текущий момент содержит значение простого типа, чаще всего Неопределено или Null.
В строке с вычислением цвета выполняются два последовательных вызова:
ВидыДней.Получить(СтрокаОформленияПериода.Дата).ЦветаВидовДней.Получить(...).Если хотя бы один из объектов — ВидыДней или ЦветаВидовДней — не инициализирован как коллекция (например, Соответствие или ФиксированноеСоответствие), выполнение кода прерывается с ошибкой.
Поставим точку останова на строке с вызовом метода Получить() и проанализируем значения контекстных переменных в табло. Как показывает практика, реквизит ВидыДней на клиенте равен Неопределено, в то время как в оригинальной конфигурации он содержит объект типа ФиксированноеСоответствие.
Выясним причину, почему это происходит:
ПроизводственныеКалендари тесно завязан на регистр сведений ДанныеПроизводственногоКалендаря, перечисление ВидыДнейПроизводственногоКалендаря и общий модуль КалендарныеГрафики. Если справочник скопирован отдельно, серверная процедура чтения данных из регистра либо падает, либо не выполняется, оставляя реквизит пустым.Неопределено.Соответствие не сериализуется при передаче между клиентом и сервером в управляемой форме. На сервере обязательно должен создаваться неизменяемый аналог — ФиксированноеСоответствие.ПолеКалендаря вызывается платформой автоматически при любой перерисовке, смене масштаба или отображении окна, иногда еще до полного завершения серверных процедур наполнения данных.Проверим серверные обработчики формы (ПриСозданииНаСервере, ПриЧтенииНаСервере или процедуру обновления отображаемого года). В них обязательно должна присутствовать инициализация реквизитов формы. Даже если данных по календарю в базе еще нет (например, создается новый элемент), реквизит ВидыДней не должен оставаться равным Неопределено.
Посмотрим на пример корректного заполнения реквизита на сервере:
&НаСервере
Процедура ИнициализироватьКоллекцииФормы()
// Создаем временное соответствие для заполнения
ВременныеВидыДней = Новый Соответствие;
// Здесь выполняется запрос к регистру сведений ДанныеПроизводственногоКалендаря
// Если записей нет, коллекция остается пустой
// Обязательно преобразуем в ФиксированноеСоответствие для передачи на клиент
ВидыДней = Новый ФиксированноеСоответствие(ВременныеВидыДней);
Если ЦветаВидовДней = Неопределено Тогда
ЦветаВидовДней = Новый ФиксированноеСоответствие(Новый Соответствие);
КонецЕсли;
КонецПроцедуры
Поскольку событие перерисовки может сработать в момент обновления формы или динамической смены года, добавим защитную проверку в самое начало клиентской процедуры КалендарьПриВыводеПериода. Это предотвратит аварийное завершение работы программы:
&НаКлиенте
Процедура КалендарьПриВыводеПериода(Элемент, ОформлениеПериода)
// Если коллекции еще не инициализированы на сервере, прерываем отрисовку
Если ВидыДней = Неопределено Или ЦветаВидовДней = Неопределено Тогда
Возврат;
КонецЕсли;
Для Каждого СтрокаОформленияПериода Из ОформлениеПериода.Даты Цикл
ВидДня = ВидыДней.Получить(СтрокаОформленияПериода.Дата);
ЦветОформленияДня = Неопределено;
Если ВидДня <> Неопределено Тогда
ЦветОформленияДня = ЦветаВидовДней.Получить(ВидДня);
КонецЕсли;
Если ЦветОформленияДня = Неопределено Тогда
ЦветОформленияДня = ОбщегоНазначенияКлиент.ЦветСтиля("ВидДняПроизводственногоКалендаряНеУказанЦвет");
КонецЕсли;
СтрокаОформленияПериода.ЦветТекста = ЦветОформленияДня;
КонецЦикла;
КонецПроцедуры
Разберем по шагам, какие связанные объекты конфигурации необходимо перенести из базы-донора для штатной работы функционала производственного календаря:
ДанныеПроизводственногоКалендаря — именно в нем хранятся даты и соответствующие им значения перечисления.ВидыДнейПроизводственногоКалендаря (со значениями: Рабочий, Суббота, Воскресенье, Праздник, Предпраздничный).ВидДняПроизводственногоКалендаряНеУказанЦвет, а также цвета для каждого вида дня (например, субботы, воскресенья, праздничных дней).КалендарныеГрафики или соответствующие процедуры БСП, считывающие данные производственного календаря.После переноса указанных метаданных и добавления защитных проверок в коде формы ошибка полностью исчезает, а календарь корректно отображает раскраску дней.