При переходе с обычных форм (например, в старых редакциях УПП) на управляемые формы (Управление холдингом, ERP, КА) разработчики часто сталкиваются с проблемой: старые методы программного изменения структуры таблиц перестают работать. Попытка добавить колонку с типом ТаблицаЗначений в существующую табличную часть на форме приводит к ошибке: "Нельзя изменять поле, содержащее объект данных формы". Разберем подробно, почему это происходит и как решить задачу современными методами платформы 1С 8.3.
Проанализируем ситуацию: в обычном приложении объект ТаблицаЗначений мог существовать непосредственно в памяти формы и гибко настраиваться. В управляемом приложении данные разделены между сервером и клиентом. То, что мы видим на экране — это не сама таблица, а специальный объект-декоратор ДанныеФормыКоллекция.
Этот объект имеет жесткую структуру, которая должна быть известна платформе для сериализации (передачи данных между сервером и клиентом). Тип ТаблицаЗначений не может быть типом колонки внутри ДанныеФормыКоллекция, так как платформа не умеет автоматически отрисовывать таблицу внутри другой таблицы в одной ячейке и передавать такую сложную вложенную структуру «на лету».
Рассмотрим по шагам основные способы обхода этого ограничения, которые позволят добиться нужного функционала.
Если вам критически важно иметь иерархическую структуру, где каждая «строка» основной таблицы может раскрываться и показывать «вложенную таблицу», лучшим инструментом будет ДеревоЗначений. Рассмотрим алгоритм его реализации:
ДеревоЗначений.Посмотрим на пример кода для заполнения такого дерева:
// На сервере
&НаСервере
Процедура ЗаполнитьДеревоНаСервере()
// Преобразуем реквизит формы в объект ДеревоЗначений для удобной работы
ДеревоОбъект = РеквизитФормыВЗначение("ДеревоДанных", Тип("ДеревоЗначений"));
// Очищаем дерево
ДеревоОбъект.Строки.Очистить();
// Создаем строку верхнего уровня (аналог строки основной ТЧ)
НоваяСтрокаРодитель = ДеревоОбъект.Строки.Добавить();
НоваяСтрокаРодитель.ID = "001";
НоваяСтрокаРодитель.Наименование = "Основной товар";
// Добавляем вложенные данные (аналог вложенной ТЗ)
ВложеннаяСтрока = НоваяСтрокаРодитель.Строки.Добавить();
ВложеннаяСтрока.Наименование = "Спецификация 1";
ВложеннаяСтрока.Значение = 100;
// Возвращаем данные в реквизит формы
ЗначениеВРеквизитФормы(ДеревоОбъект, "ДеревоДанных");
КонецПроцедуры
Это наиболее «правильный» с точки зрения интерфейсов 1С подход. Вместо того чтобы пытаться втиснуть таблицу в таблицу, мы разделим интерфейс на две части.
Выясним причину, почему это удобно: пользователь видит основную таблицу, и при выделении строки в ней (событие ПриАктивизацииСтроки), вторая таблица на форме мгновенно перерисовывается, показывая связанные данные.
Для реализации выполните следующие действия:
ТаблицаЗначений).ПриАктивизацииСтроки.Пример реализации связи:
&НаКлиенте
Процедура ОсновнаяТаблицаПриАктивизацииСтроки(Элемент)
ТекущиеДанные = Элемент.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
ОбновитьВложеннуюТаблицу(ТекущиеДанные.КлючСвязи);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ОбновитьВложеннуюТаблицу(КлючСвязи)
// Здесь мы ищем данные, соответствующие ключу, и заполняем вторую таблицу
// Например, из общего соответствия или запросом
КоллекцияВложенныхДанных = НайтиДанныеПоКлючу(КлючСвязи);
ЗначениеВРеквизитФормы(КоллекцияВложенныхДанных, "ВложеннаяТаблицаФормы");
КонецПроцедуры
Если вложенная таблица нужна вам не для редактирования пользователем «в ячейке», а для хранения результатов расчетов или последующего вывода в макет, используйте упаковку данных в строку. Это позволяет обойти ограничение типов ДанныеФормыКоллекция.
Разберем по шагам, как упаковать ТаблицуЗначений:
Строка (неограниченной длины).Рассмотрим пример использования ЗначениеВСтрокуВнутр (или более современного JSON):
// Упаковка в строку
ДанныеСтроки.ВложеннаяТЗ_Строкой = ЗначениеВСтрокуВнутр(ТЗ_АЗСт);
// Распаковка обратно в объект
ТЗ_ДляОбработки = ЗначениеИзСтрокиВнутр(ДанныеСтроки.ВложеннаяТЗ_Строкой);
Важный момент: если вы используете платформу выше 8.3.6, мы рекомендуем использовать JSON, так как он работает быстрее и занимает меньше места:
// Сериализация ТЗ в JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, ТЗ_ДляУпаковки);
РезультатСтрока = ЗаписьJSON.Закрыть();
Этот метод подходит для временных расчетов в рамках одной сессии работы с формой. Вместо того чтобы хранить тяжелые данные в реквизитах формы (что замедляет передачу данных между сервером и клиентом), мы можем хранить их во временном хранилище.
Проанализируем ситуацию: в колонку основной таблицы мы записываем только уникальный адрес (Строка), по которому на сервере можно получить полноценный объект ТаблицаЗначений.
// Помещаем таблицу в хранилище и сохраняем адрес в строке ТЧ
АдресХранилища = ПоместитьВоВременноеХранилище(ТЗ_АЗСт, ЭтаФорма.УникальныйИдентификатор);
НоваяСтрока.АдресДанных = АдресХранилища;
// Позже, когда данные нужны для макета
ТЗ_ИзХранилища = ПолучитьИзВременногоХранилища(ЭлементТЧ.АдресДанных);
Мы проанализировали проблему невозможности прямого добавления ТаблицыЗначений в колонку экранной таблицы. Подведем итоги выбора решения:
ДеревоЗначений.Master-Detail с двумя таблицами.JSON-сериализацию или Временное хранилище.Использование данных методов позволит вам избежать ошибки изменения поля данных формы и обеспечит стабильную работу обработки в режиме управляемого приложения.