Почему ТекущиеДанные динамического списка в расширении формы подбора возвращают Неопределено и как это исправить?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Выясняем причину: механизм ленивой инициализации управляемых форм

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

Эти таблицы обычно располагаются на разных страницах одной панели (например, группы страниц СтраницыСписков). С точки зрения оптимизации производительности и экономии трафика между сервером и тонким клиентом, платформа «1С» использует механизм отложенного (ленивого) рендеринга и считывания данных для скрытых элементов формы.

Если страница, на которой физически расположена таблица СписокРасширенныйПоискНоменклатура, в данный момент скрыта (неактивна), платформа не инициализирует строки этой таблицы на клиенте и не запрашивает для нее данные с сервера. Как результат:

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

Способ 1. Универсальный обход элементов на клиенте (устойчивый код)

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

Рассмотрим первый вариант реализации — через проверку того, какая страница панели сейчас выбрана пользователем:


&НаКлиенте
Процедура Расш1_ДобавитьТоварПосле(Команда)
    
    ТекущиеДанные = Неопределено;
    АктивнаяСтраница = Элементы.СтраницыСписков.ТекущаяСтраница;
    
    Если АктивнаяСтраница = Элементы.ГруппаСтраницаРасширенныйПоиск Тогда
        ТекущиеДанные = Элементы.СписокРасширенныйПоискНоменклатура.ТекущиеДанные;
    ИначеЕсли АктивнаяСтраница = Элементы.ГруппаСтраницаСтандартныйПоиск Тогда
        ТекущиеДанные = Элементы.СписокСтандартныйПоискНоменклатура.ТекущиеДанные;
    КонецЕсли;
    
    Если ТекущиеДанные = Неопределено Тогда
        ПоказатьПредупреждение(, NStr("ru = 'Пожалуйста, выберите товар из списка!'"));
        Возврат;
    КонецЕсли;
    
    // Дальнейшая обработка полученных данных
    ОбработатьВыбранныйТовар(ТекущиеДанные);
    
КонецПроцедуры

Если структура страниц сложная или может меняться при обновлениях, применим еще более гибкий и лаконичный подход — последовательный опрос таблиц на наличие заполненного свойства ТекущиеДанные:


&НаКлиенте
Процедура Расш1_ЗаполнитьТабличнуюЧасть()
    
    ТекущиеДанные = Элементы.СписокРасширенныйПоискНоменклатура.ТекущиеДанные;
    
    Если ТекущиеДанные = Неопределено Тогда
        // Если в расширенном списке пусто, пробуем получить данные из стандартного
        ТекущиеДанные = Элементы.СписокСтандартныйПоискНоменклатура.ТекущиеДанные;
    КонецЕсли;
    
    Если ТекущиеДанные = Неопределено Тогда
        // Если и там пусто, возможно, используется таблица характеристик или аналогов
        // Проверяем все доступные источники данных на форме подбора
        Если Элементы.Найти("СписокХарактеристикиНоменклатуры") <> Неопределено Тогда
            ТекущиеДанные = Элементы.СписокХарактеристикиНоменклатуры.ТекущиеДанные;
        КонецЕсли;
    КонецЕсли;
    
    Если ТекущиеДанные = Неопределено Тогда
        Возврат; // Данные не выбраны ни в одном из списков
    КонецЕсли;
    
    // Работаем с универсальной переменной ТекущиеДанные...
    ПровестиАнализНоменклатуры(ТекущиеДанные.Номенклатура);
    
КонецПроцедуры

Способ 2. Программное изменение формы вместо визуального редактирования (Best Practice)

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

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

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

Рассмотрим практический пример программного добавления колонки и кнопки на форму подбора:


&После("ПриСозданииНаСервере")
Процедура Расш1_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // 1. Программно добавляем колонку "ОстатокНаСкладе" в динамические списки
    ДобавитьКолонкуВТаблицуФормы("СписокСтандартныйПоискНоменклатура", "ОстатокНаСкладе", "Остаток");
    ДобавитьКолонкуВТаблицуФормы("СписокРасширенныйПоискНоменклатура", "ОстатокНаСкладе", "Остаток");
    
КонецПроцедуры

&НаСервере
Процедура ДобавитьКолонкуВТаблицуФормы(ИмяТаблицыФормы, ИмяПутиКДанным, ЗаголовокКолонки)
    
    ТаблицаФормы = Элементы.Найти(ИмяТаблицыФормы);
    Если ТаблицаФормы <> Неопределено Тогда
        
        ИмяНовогоЭлемента = ИмяТаблицыФормы + "_" + ИмяПутиКДанным;
        Если Элементы.Найти(ИмяНовогоЭлемента) = Неопределено Тогда
            
            НоваяКолонка = Элементы.Добавить(ИмяНовогоЭлемента, Тип("ПолеФормы"), ТаблицаФормы);
            НоваяКолонка.Вид = ВидПоляФормы.ПолеВвода;
            НоваяКолонка.ПутьКДанным = ИмяТаблицыФормы + ".Данные." + ИмяПутиКДанным;
            НоваяКолонка.Заголовок = ЗаголовокКолонки;
            НоваяКолонка.ТолькоПросмотр = Истина;
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

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

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

Для обновления режима совместимости и структуры формы в расширении выполните следующие шаги:

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

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

← На главную