При разработке интерфейсов на платформе 1С:Предприятие нередко возникает необходимость связать данные по принципу «один ко многим». Типичный пример: в строке таблицы выводится контрагент, а в соседней ячейке необходимо показать список его договоров с возможностью проставления отметок (флажков). Разберем, возможно ли поместить одну таблицу внутрь ячейки другой таблицы и какие типовые архитектурные решения существуют для реализации этой задачи.
Проанализируем техническую сторону вопроса. Если на сервере в объекте ТаблицаЗначений создать колонку с типом ТаблицаЗначений или СписокЗначений, платформа не выдаст синтаксической ошибки при инициализации структуры. Однако при попытке визуализировать такие данные на управляемой форме элемент формы Таблица не отобразит вложенную таблицу.
Элемент формы Таблица принципиально не может содержать другой элемент Таблица внутри своей ячейки. Ячейки таблицы формы предназначены только для отображения скалярных типов данных (строка, число, дата, булево, ссылки на объекты базы данных) либо элементов управления типа ПолеВвода, ПолеФлажка и ПолеНадписи. Сложные коллекции значений внутри ячеек интерфейсом формы игнорируются.
Выясним, какие альтернативные способы позволяют решить прикладную задачу пользователя удобно и без нарушения стандартов разработки платформы 1С.
Это классический, наиболее производительный и привычный для пользователей вариант организации интерфейса. Рассмотрим его реализацию по шагам.
ТаблицаЗначений: например, ТаблицаКонтрагентов (основная) и ТаблицаДоговоров (подчиненная).Договор и Пометка (тип Булево).ПриАктивизацииСтроки. При смене текущей строки в первой таблице программно устанавливаем отбор во второй таблице.Посмотрим на пример установки отбора во второй таблице при смене активной строки в первой:
&НаКлиенте
Процедура ТаблицаКонтрагентовПриАктивизацииСтроки(Элемент)
СтрокаТаблицы = Элемент.ТекущиеДанные;
Если СтрокаТаблицы = Неопределено Тогда
Элементы.ТаблицаДоговоров.ОтборСтрок = Неопределено;
Возврат;
КонецЕсли;
// Устанавливаем отбор подчиненной таблицы по контрагенту
Элементы.ТаблицаДоговоров.ОтборСтрок = Новый ФиксированнаяСтруктура("Контрагент", СтрокаТаблицы.Контрагент);
КонецПроцедуры
Такой подход полностью разделяет логику отображения, избавляет от перегрузки интерфейса и работает максимально быстро даже на больших объемах данных.
Если бизнес-требование категорически настаивает на представлении данных в едином окне, разберем перевод таблицы в иерархическую структуру. Объект ДеревоЗначений идеально подходит для отображения подчиненных записей.
ДеревоЗначений.Наименование, Договор, Пометка.Таблица, поддерживающий раскрывающиеся узлы.Посмотрим на пример программного заполнения дерева значений на сервере:
&НаСервере
Процедура ЗаполнитьДанныеДерева()
ДеревоОбъект = ДанныеФормыВЗначение(РеквизитДерево, Тип("ДеревоЗначений"));
ДеревоОбъект.Строки.Очистить();
Для Каждого ТекКонтрагент Из СписокКонтрагентов Цикл
СтрокаКонтрагента = ДеревоОбъект.Строки.Добавить();
СтрокаКонтрагента.Наименование = ТекКонтрагент.Наименование;
Для Каждого ТекДоговор Из ПолучитьДоговорыКонтрагента(ТекКонтрагент) Цикл
СтрокаДоговора = СтрокаКонтрагента.Строки.Добавить();
СтрокаДоговора.Договор = ТекДоговор;
СтрокаДоговора.Пометка = Ложь;
КонецЦикла;
КонецЦикла;
ЗначениеВДанныеФормы(ДеревоОбъект, РеквизитДерево);
КонецПроцедуры
В результате пользователь получает единую таблицу, где каждого контрагента можно развернуть и отметить нужные договоры флажками.
Рассмотрим вариант, когда строку таблицы делить на подстроки нельзя, но необходимо прямо в ячейке выбрать несколько договоров и видеть их список. В этом случае колонка таблицы делается строковой, а интерактивный выбор организуется через отдельное окно.
КнопкаВыбора = Истина и РедактированиеТекста = Ложь.НачалоВыбора перехватываем действие пользователя и открываем диалог отметки элементов списка.ПоказатьОтметкуЭлементов().Посмотрим на пример реализации обработчика начала выбора:
&НаКлиенте
Процедура ТаблицаСписокДоговоровНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ТекущаяСтрока = Элементы.Таблица.ТекущиеДанные;
Если ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
СписокВыбора = ПолучитьСписокДоговоровКонтрагента(ТекущаяСтрока.Контрагент);
Оповещение = Новый ОписаниеОповещения("ПослеВыбораДоговоров", ЭтотОбъект, ТекущаяСтрока);
СписокВыбора.ПоказатьОтметкуЭлементов(Оповещение, "Выберите договоры");
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыбораДоговоров(РезультатВыбора, ДополнительныеПараметры)
Если РезультатВыбора = Неопределено Тогда
Возврат;
КонецЕсли;
СтрокаОтображения = "";
Для Каждого ЭлементСписка Из РезультатВыбора Цикл
Если ЭлементСписка.Пометка Тогда
СтрокаОтображения = СтрокаОтображения + ?(ПустаяСтрока(СтрокаОтображения), "", ", ") + Строка(ЭлементСписка.Значение);
КонецЕсли;
КонецЦикла;
ДополнительныеПараметры.СписокДоговоров = СтрокаОтображения;
КонецПроцедуры
Если интерактивная отметка флажками внутри самой ячейки не требуется, а нужно только вывести несколько договоров в пределах строки, проанализируем настройку многострочного поля:
МногострочныйРежим = Истина.Символы.ПС.Попытка напрямую встроить элемент Таблица в ячейку противоречит архитектуре платформы 1С. Наиболее эргономичным решением остается разделение интерфейса на две связанные таблицы (Master-Detail) или использование ДереваЗначений, если требуется сохранить монолитный вид древовидного реестра.