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

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

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

Проблема 1: Директивы компиляции в модуле объекта

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

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

Проблема 2: Разрыв связи между формой и объектом

Выясним основную причину «пустой таблицы». Когда мы работаем с управляемой формой, мы взаимодействуем не с самим объектом базы данных (или обработки), а с его «проекцией» — реквизитом Объект (тип ДанныеФормыСтруктура или ДанныеФормыКоллекция для таблиц). Если процедура заполнения находится в модуле объекта, алгоритм работы обычно выглядит так:

  1. На форме срабатывает команда (Клиент).
  2. Вызывается серверная процедура формы (Сервер).
  3. Данные формы преобразуются в реальный объект обработки.
  4. Вызывается метод объекта.
  5. Результат должен быть возвращен обратно в форму.

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


&НаСервере
Процедура ЗаполнитьТЧНаСервере()
    // 1. Конвертируем данные формы в объект обработки
    ОбъектОбработка = РеквизитФормыВЗначение("Объект");
    
    // 2. Вызываем экспортный метод из модуля объекта
    ОбъектОбработка.ПрочитатьИзФайла();
    
    // 3. Важнейший шаг: возвращаем измененные данные объекта назад в форму
    ЗначениеВРеквизитФормы(ОбъектОбработка, "Объект");
КонецПроцедуры

Без вызова ЗначениеВРеквизитФормы все изменения, внесенные в процедуре ПрочитатьИзФайла, останутся в оперативной памяти сервера внутри временного объекта ОбъектОбработка и будут уничтожены сразу после завершения процедуры. Пользователь на экране ничего не увидит.

Проблема 3: Нюансы использования Построителя Запроса

В коде автора для чтения данных из ТабличныйДокумент используется ПостроительЗапроса. Это мощный инструмент, который позволяет быстро превратить визуальную таблицу в таблицу значений. Однако проанализируем важные требования к этому методу:

Во-первых, область, передаваемая в ОписаниеИсточникаДанных, должна быть корректной. Автор использует ТабличныйДокумент.Область(3,1, Высота, Ширина). Это означает, что чтение начинается с 3-й строки. Критически важно, чтобы первая строка этой области (в данном случае 3-я строка файла) содержала заголовки колонок. Имена этих заголовков должны в точности совпадать с именами полей, к которым идет обращение (Улица, Дом, ДатаПлатежа и т.д.).

Во-вторых, если в заголовке файла написано "Дата платежа" (с пробелом), ПостроительЗапроса не сможет создать колонку с таким именем, так как в 1С имена колонок таблицы значений не могут содержать пробелов. Он заменит её на ИмяКолонкиN. В итоге обращение СтрокаТч.ДатаПлатежа вызовет ошибку. Рекомендуется всегда проверять результат выгрузки отладчиком.

Правильная реализация в модуле объекта

Посмотрим, как должен выглядеть очищенный от лишних директив код в модуле объекта:


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

Рекомендации по работе с файлами в клиент-серверном режиме

Проанализируем еще один тонкий момент. Автор использует ПутьКФайлу напрямую на сервере. Если ваша база работает в клиент-серверном варианте, сервер 1С ничего не знает о диске C:\ на вашем компьютере. Попытка вызвать ТабличныйДокумент.Прочитать(ПутьКФайлу) на сервере приведет к ошибке "Файл не найден".

Правильный алгоритм работы с файлами в управляемом приложении:

  1. На клиенте: выбираем файл и помещаем его во временное хранилище с помощью функции ПоместитьФайл(). Получаем АдресВХранилище.
  2. Передаем адрес на сервер: в процедуру формы ЗаполнитьТЧНаСервере(АдресВХранилище).
  3. На сервере: извлекаем данные из хранилища.

Пример получения данных из хранилища:


ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(АдресВХранилище);
// Создаем поток для чтения табличного документа из памяти
ЧтениеДанных = Новый ЧтениеДанных(ДвоичныеДанныеФайла);
ТабДок.Прочитать(ЧтениеДанных);

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

← На главную