Почему не работает ТабДок.Присоединить() в управляемых формах и как это исправить?

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

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

Разберем механизм работы методов Вывести() и Присоединить()

Прежде чем переходить к коду, нам необходимо четко понимать, как платформа 1С управляет «курсором» в табличном документе. Это критически важно для понимания логики построения отчета:

  1. Метод Вывести() — всегда добавляет новую область вниз. После его вызова виртуальный указатель печати перемещается на начало следующей строки.
  2. Метод Присоединить() — добавляет область справа от последней выведенной области в той же самой строке.

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

Анализируем исходный код формирования отчета

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


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

Выясним причину ошибки

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

Важный момент: Если вы используете метод ПолучитьОбласть("Строка|Колонка"), убедитесь, что в макете области пересечения определены корректно. Если вы получили область Строка1|Часть1, а затем пытаетесь присоединить область, которая в макете не является частью той же горизонтальной полосы, платформа может не «понять», куда именно нужно приклеить данные.

Также проанализируем параметры метода. Использование параметров уровня: ТабДок.Присоединить(Область, Строка.Уровень) может влиять на группировку колонок. Если уровень передан неверно, колонки могут сгруппироваться так, что станут невидимыми (свернутыми) по умолчанию.

Рекомендации по исправлению и лучшие практики

Для того чтобы метод Присоединить() работал стабильно, воспользуемся следующими правилами:

  1. Проверка макета: Убедитесь, что присоединяемая область в макете имеет ту же высоту, что и область, к которой идет присоединение. Если высоты строк в разных секциях макета различаются, Присоединить() может отработать некорректно.
  2. Использование явных пересечений: Всегда определяйте области в макете как пересечения строк и колонок. Например, Макет.ПолучитьОбласть("СтрокаДанных|КолонкаМесяц"). Это гарантирует, что 1С возьмет конкретный прямоугольник ячеек.
  3. Контроль «пустых» выводов: Проверьте, не вызывается ли где-то в коде пустой ТабДок.Вывести() без параметров или с пустой областью. Это сбросит каретку на новую строку, и ваше присоединение уйдет «в никуда».
  4. Отладка на сервере: В управляемых формах печать часто идет в процедуре &НаСервере. Если ТабличныйДокумент является реквизитом формы, убедитесь, что вы работаете именно с ним, а не создаете новый локальный объект Новый ТабличныйДокумент, который уничтожается при выходе из процедуры.

Пример правильной структуры формирования

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


// Сначала выводим основную (левую) часть строки
ОбластьЛево = Макет.ПолучитьОбласть("Строка|ЛеваяЧасть");
ОбластьЛево.Параметры.Номенклатура = ТекущаяСтрока.Номенклатура;
ТабДок.Вывести(ОбластьЛево); // Указатель теперь в конце этой области

// В цикле присоединяем колонки
Для Каждого ТекМесяц Из СписокМесяцев Цикл
    ОбластьКолонка = Макет.ПолучитьОбласть("Строка|КолонкаДанных");
    ОбластьКолонка.Параметры.Значение = НайтиПродажи(ТекМесяц);
    ТабДок.Присоединить(ОбластьКолонка); // Присоединяем справа
КонецЦикла;

// В конце присоединяем итоговую правую часть
ОбластьПраво = Макет.ПолучитьОбласть("Строка|ПраваяЧасть");
ОбластьПраво.Параметры.Итого = ТекущаяСтрока.Итого;
ТабДок.Присоединить(ОбластьПраво);

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

← На главную