Почему таблица значений на обычной форме 1С остается пустой и как это исправить?

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

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

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

Выясняем причину: почему рвется связь данных?

Для начала проанализируем код, который изначально написал автор темы:


Результат = Запрос.Выполнить();
ЭтотОбъект.тзЦены = Результат.Выгрузить();
ЭтотОбъект.ПолучитьФорму("Форма").ОткрытьМодально();

На первый взгляд всё логично: результат запроса выгружается в реквизит объекта тзЦены, после чего открывается форма, где табличное поле связано с этим самым реквизитом через свойство Данные. Однако на экране мы видим пустую таблицу.

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

  1. При создании и инициализации объекта обработки в памяти выделяется область под реквизит тзЦены. Назовем этот экземпляр таблицы значений «Таблица №1» (она пустая).
  2. Когда создается форма обработки, элемент управления Табличное поле жестко связывается с этой конкретной «Таблицей №1».
  3. Затем в коде модуля выполняется строка ЭтотОбъект.тзЦены = Результат.Выгрузить();. Метод Выгрузить() создает в памяти совершенно новый объект — «Таблицу №2», в которую помещает строки из запроса.
  4. Оператор присваивания = перенаправляет ссылку реквизита ЭтотОбъект.тзЦены на новый объект — «Таблицу №2».
  5. При этом наше табличное поле на форме по-прежнему остается связанным со старой, пустой «Таблицей №1». Связь между интерфейсом и актуальными данными безвозвратно разрывается.

Разбор ошибки «Метод объекта не обнаружен (СоздатьКолонки)»

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


ЭлементыФормы.ТабличноеПолеЦены.Значение = Результат.Выгрузить();
ЭлементыФормы.ТабличноеПолеЦены.СоздатьКолонки();

Однако при выполнении этого кода в модуле объекта возникает критическая ошибка выполнения. Выясним причину этой ошибки:

  1. Контекст исполнения. Модуль объекта не имеет прямого доступа к коллекции ЭлементыФормы. Эта коллекция доступна только внутри модуля самой формы. Платформа 1С просто не понимает, откуда взялась переменная ЭлементыФормы в модуле объекта, и выдает ошибку.
  2. Неверный адресат метода. Метод СоздатьКолонки() является методом элемента управления формы (класс ТабличноеПоле). У самого объекта типа ТаблицаЗначений (прикладного объекта данных) такого метода нет. Если попытаться применить его к значению ТЗ, система закономерно сообщит об отсутствии метода.

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

Способ 1. Заполнение существующего экземпляра таблицы значений (Рекомендуемый)

Самый простой и правильный способ работы в модуле объекта — не заменять ссылку на таблицу значений новой ссылкой, а загрузить новые данные в уже существующий, изначально связанный с формой экземпляр ТЗ. Для этого мы используем метод Загрузить().

Рассмотрим пример кода для модуля объекта:


// Выполняем запрос к базе данных
Результат = Запрос.Выполнить();

// Очищаем существующую таблицу значений, чтобы удалить старые данные
ЭтотОбъект.тзЦены.Очистить();

// Загружаем данные из результата запроса в ту же самую область памяти
ЭтотОбъект.тзЦены.Загрузить(Результат.Выгрузить());

// Теперь открываем форму — связь данных не потерялась, таблица заполнится автоматически
ЭтотОбъект.ПолучитьФорму("Форма").ОткрытьМодально();

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

Способ 2. Программное связывание данных при получении формы

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

Проанализируем, как правильно реализовать этот подход в модуле объекта:


// Получаем объект формы в переменную, но не открываем ее сразу
ФормаОбработки = ЭтотОбъект.ПолучитьФорму("Форма");

// Передаем новый экземпляр таблицы значений напрямую в значение табличного поля на форме
ФормаОбработки.ЭлементыФормы.ТабличноеПолеЦены.Значение = Результат.Выгрузить();

// Принудительно заставляем элемент формы перестроить визуальные колонки под новую структуру данных
ФормаОбработки.ЭлементыФормы.ТабличноеПолеЦены.СоздатьКолонки();

// Открываем настроенную форму модально
ФормаОбработки.ОткрытьМодально();

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

Способ 3. Перенос логики заполнения в модуль формы

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

Выполним следующие шаги:

  1. Оставляем реквизит тзЦены в качестве реквизита обработки.
  2. Связываем табличное поле на форме с этим реквизитом стандартным образом.
  3. В модуле формы создаем предопределенный обработчик события ПриОткрытии:

Процедура ПриОткрытии()
    
    // Формируем и выполняем запрос непосредственно в контексте формы
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ... "; // Ваш текст запроса
    
    Результат = Запрос.Выполнить();
    
    // Перезаписываем реквизит обработки новым значением
    ЭтотОбъект.тзЦены = Результат.Выгрузить();
    
    // Восстанавливаем программную связь элемента формы с новым объектом данных
    ЭлементыФормы.ТабличноеПолеЦены.Значение = ЭтотОбъект.тзЦены;
    
    // Пересоздаем колонки отображения
    ЭлементыФормы.ТабличноеПолеЦены.СоздатьКолонки();
    
КонецПроцедуры

Способ 4. Использование Табличной части (ТЧ) вместо Таблицы значений

Если специфика вашей задачи допускает использование метаданных, то лучшим решением (как справедливо отмечено в Сообщении 8) будет отказ от реквизита типа ТаблицаЗначений в пользу полноценной Табличной части объекта обработки.

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

Для реализации этого способа выполните следующие действия:

  1. В конфигураторе добавьте к вашей внешней обработке Табличную часть с именем, например, Цены. Добавьте в нее необходимые реквизиты (колонки).
  2. Разместите на форме Табличное поле и укажите в качестве источника данных табличную часть ЭтотОбъект.Цены.
  3. В модуле объекта напишите лаконичный код заполнения:

// Загрузка данных в табличную часть происходит одной строкой и не ломает связь с формой
ЭтотОбъект.Цены.Загрузить(Результат.Выгрузить());

// Открываем форму — все данные будут на месте без дополнительных манипуляций
ЭтотОбъект.ПолучитьФорму("Форма").ОткрытьМодально();

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

← На главную