При разработке отчетов в 1С с использованием макетов и табличных документов программисты часто сталкиваются с ситуацией, когда расшифровка (drill-down) работает некорректно: на какую бы ячейку в строке пользователь ни нажал, система выдает данные, относящиеся только к последней колонке. Эта проблема кажется мистической, ведь в коде мы явно присваиваем разные значения разным параметрам расшифровки. Разберем подробно, почему так происходит, и как правильно организовать передачу данных в обработчик расшифровки.
Рассмотрим типичный сценарий. У нас есть цикл, в котором мы обходим таблицу значений (например, со складами и продажами) и выводим строки в табличный документ. Для каждой ячейки (Склад, Продажа) мы хотим передать свой набор данных в расшифровку, чтобы при клике на склад открывалась форма склада, а при клике на сумму — отчет по продажам. Типичный, но ошибочный код выглядит следующим образом:
Для Каждого стр из тзЗапросСклады Цикл
Строка = Макет.ПолучитьОбласть("Строка");
Строка.Параметры.Склад = стр.Склад;
// Создаем структуру ОДИН РАЗ
СтруктураРасшифровки = Новый Структура;
СтруктураРасшифровки.Вставить("Склад", стр.Склад);
// Заполняем для первой ячейки
СтруктураРасшифровки.Вставить("Поле", 1);
Строка.Параметры.РасшифровкаСклад = СтруктураРасшифровки;
// Пытаемся переопределить значение для второй ячейки в ТОЙ ЖЕ структуре
СтруктураРасшифровки.Вставить("Поле", 2);
Строка.Параметры.РасшифровкаПродажа = СтруктураРасшифровки;
Таб.Вывести(Строка);
КонецЦикла;
В результате, при нажатии на любую из ячеек в сформированном отчете, значение Расшифровка.Поле всегда будет равно 2. Почему? Давайте разбираться в механизмах работы платформы.
В языке 1С объекты таких типов как Структура, Массив, ТаблицаЗначений являются ссылочными. Это означает, что в переменной СтруктураРасшифровки хранится не сама таблица с данными, а адрес (указатель) на область памяти, где этот объект находится.
Проанализируем пошагово, что происходит в памяти компьютера:
СтруктураРасшифровки = Новый Структура; создает объект в памяти (условно, по адресу №100).Поле = 1. Теперь объект по адресу №100 содержит значение 1.Строка.Параметры.РасшифровкаСклад = СтруктураРасшифровки; говорит системе: "Параметр расшифровки этой ячейки должен смотреть на объект по адресу №100".Поле = 2 в той же самой структуре. Объект по адресу №100 теперь содержит значение 2.Строка.Параметры.РасшифровкаПродажа = СтруктураРасшифровки; говорит системе: "Параметр расшифровки второй ячейки тоже должен смотреть на адрес №100".В итоге обе ячейки ссылаются на один и тот же экземпляр структуры. Поскольку последним записанным значением было "2", то при активации расшифровки в любой ячейке 1С обратится к этому объекту и увидит там "2".
Чтобы каждая ячейка имела свои уникальные данные расшифровки, необходимо для каждого параметра создавать новый экземпляр структуры. Это разорвет связь между параметрами разных ячеек. Посмотрим на исправленный фрагмент кода:
Для Каждого стр из тзЗапросСклады Цикл
Строка = Макет.ПолучитьОбласть("Строка");
// Расшифровка для Склада - создаем отдельный объект
ДанныеСклада = Новый Структура;
ДанныеСклада.Вставить("Склад", стр.Склад);
ДанныеСклада.Вставить("ТипПоля", "Склад");
Строка.Параметры.РасшифровкаСклад = ДанныеСклада;
// Расшифровка для Продаж - создаем ЕЩЕ ОДИН отдельный объект
ДанныеПродаж = Новый Структура;
ДанныеПродаж.Вставить("Склад", стр.Склад);
ДанныеПродаж.Вставить("ТипПоля", "Продажа");
Строка.Параметры.РасшифровкаПродажа = ДанныеПродаж;
Таб.Вывести(Строка);
КонецЦикла;
Теперь РасшифровкаСклад и РасшифровкаПродажа указывают на разные области памяти, и изменение одной никак не влияет на другую.
После того как мы правильно вывели данные в табличный документ, нам нужно их обработать. Рассмотрим процедуру ОбработкаРасшифровки. Важно помнить, что если мы сами обрабатываем клик, стандартную обработку 1С нужно отключить.
Процедура ТабличныйДокументОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
// Если в ячейку записана структура (наш случай)
Если ТипЗнч(Расшифровка) = Тип("Структура") Тогда
// Отключаем стандартное открытие карточки объекта
СтандартнаяОбработка = Ложь;
Если Расшифровка.ТипПоля = "Склад" Тогда
// Открываем форму справочника
ПоказатьЗначение(, Расшифровка.Склад);
ИначеЕсли Расшифровка.ТипПоля = "Продажа" Тогда
// Например, открываем другой отчет с фильтром по складу
ПараметрыОтчета = Новый Структура("Склад", Расшифровка.Склад);
ОткрытьФорму("Отчет.ПродажиДетально.Форма", ПараметрыОтчета);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Проанализируем еще несколько важных нюансов, которые помогут сделать ваши отчеты более надежными:
Элемент в процедуре расшифровки — это само поле табличного документа. Через него можно получить доступ к текущей области: Элемент.ТекущаяОбласть. Это позволяет узнать адрес ячейки (R1C1), её текст или даже цвет фона, если это необходимо для логики программы.Строка) внутри цикла, убедитесь, что при каждом новом витке цикла вы либо заново получаете область из макета (Макет.ПолучитьОбласть("...")), либо очищаете параметры. Однако, ПолучитьОбласть уже создает копию, поэтому параметры там будут пустыми.ТипПоля = "Склад"). Это делает код гораздо более читаемым и защищает от ошибок при добавлении новых колонок в отчет.Использование структур в расшифровке — это мощный инструмент, позволяющий передавать в обработчик не одно значение, а целый контекст (период, организацию, настройки фильтров). Главное — помнить о правилах работы с объектами в памяти 1С и всегда создавать новые экземпляры данных для каждой независимой области отчета.