Почему в расшифровке отчета 1С всегда открывается один и тот же (последний) документ?

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

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

Суть проблемы и механизм работы области макета

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

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

Анализ ошибочного кода

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


// ... код первого формирования ...
ТабДок.Очистить(); 
// ... настройки оформления ...
Пока ВыборкаЗаказ.Следующий Цикл
    // Здесь заполняются текстовые параметры
    Строка.Параметры.НомерПП = а;
    Строка.Параметры.НомерЗаказа = ПолучитьНомер(ВыборкаЗаказ.Ссылка.Номер);
    
    // ОШИБКА: Пропущен параметр расшифровки!
    // Во втором цикле отсутствует строка:
    // Строка.Параметры.РНомерЗаказа = ВыборкаЗаказ.Ссылка;
    
    ТабДок.Вывести(Строка);
КонецЦикла;

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

Пошаговое решение проблемы

Для исправления ситуации необходимо придерживаться следующих правил при работе с макетами:

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

Правильный вариант заполнения параметров в цикле должен выглядеть так:


Пока Выборка.Следующий() Цикл
    // Получаем область заново или гарантированно заполняем ВСЕ параметры
    СекцияСтрока = Макет.ПолучитьОбласть("Строка");
    
    СекцияСтрока.Параметры.НомерЗаказа = Выборка.Номер;
    // Явно заполняем параметр расшифровки на каждой итерации!
    СекцияСтрока.Параметры.ПараметрРасшифровкиДокумента = Выборка.Ссылка;
    
    ТабДок.Вывести(СекцияСтрока);
КонецЦикла;

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

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

Разберем пример:


// Выводим область
ТабДок.Вывести(СекцияСтрока);

// Определяем координаты только что выведенной строки
НомерПоследнейСтроки = ТабДок.ВысотаТаблицы;
// Назначаем расшифровку конкретной ячейке (например, в колонке 3)
Ячейка = ТабДок.Область(НомерПоследнейСтроки, 3);
Ячейка.Расшифровка = Выборка.Ссылка;

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

Как проверить причину ошибки (Отладка)

Если вы столкнулись с подобной проблемой, проанализируйте ситуацию по следующим шагам:

  1. В режиме конфигуратора поставьте точку останова на строке ТабДок.Вывести(Строка).
  2. В табло (Shift+F9) вычислите выражение Строка.Параметры.ИмяВашегоПараметраРасшифровки.
  3. Прошагайте несколько итераций цикла. Если значение параметра не меняется между шагами Следующий(), значит, в коде отсутствует команда присваивания ссылки в этот параметр.
  4. Проверьте макет: убедитесь, что у ячейки в свойстве "Параметр расшифровки" написано именно то имя, к которому вы обращаетесь в коде через .Параметры....

Помните, что метод ТабДок.Очистить() удаляет только содержимое результирующего документа, но не обнуляет переменные областей макета, которые вы уже получили с помощью ПолучитьОбласть(). Будьте внимательны при повторном использовании объектов областей!

← На главную