При динамической работе с таблицами в интерфейсе обычных форм разработчики часто сталкиваются с ситуацией: после добавления колонок в объект ТаблицаЗначений и программного сдвига колонок в табличном поле любое последующее добавление новой колонки возвращает все сдвинутые элементы на исходные позиции. Разберем детально, почему так происходит и как правильно организовать работу с динамическими колонками.
Проанализируем исходный фрагмент кода, приводящий к ошибке:
Процедура ДобавитьКолонкаНажатие(Элемент)
ТЗ.Колонки.Добавить();
ЭлементыФормы.ТабПоле.Значение = ТЗ;
ЭлементыФормы.ТабПоле.СоздатьКолонки();
КонецПроцедуры
Выясним причину сброса положения колонок. Метод СоздатьКолонки() у объекта ТабличноеПоле не выполняет «умное обновление» или добавление только недостающих элементов. Этот метод полностью очищает существующую коллекцию колонок табличного поля и генерирует её заново на основании текущей структуры источника данных (ТаблицаЗначений).
В результате вызова метода происходят следующие изменения:
ЭлементыФормы.ТабПоле.Колонки полностью уничтожается.ТаблицаЗначений.ПолеВвода, Флажок) безвозвратно сбрасываются к значениям по умолчанию.ЭлементыФормы.ТабПоле.Значение = ТЗ также является избыточным, так как табличное поле уже связано по ссылке с объектом в памяти.Рассмотрим несколько правильных способов решения этой задачи в зависимости от требований к коду.
Если структура таблицы уже сформирована и пользователю требуется добавлять колонки «на лету», не следует вызывать СоздатьКолонки(). Правильный подход — параллельно добавить колонку в источник данных и в визуальную таблицу формы.
Посмотрим на пример реализации:
// 1. Добавляем колонку в источник данных
ИмяНовойКолонки = "Колонка_" + Формат(ТЗ.Колонки.Количество() + 1, "ЧГ=0");
ТипКолонки = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2));
КолонкаТЗ = ТЗ.Колонки.Добавить(ИмяНовойКолонки, ТипКолонки, "Новая колонка");
// 2. Добавляем колонку в табличное поле без сброса структуры
КолонкаТП = ЭлементыФормы.ТабПоле.Колонки.Добавить(ИмяНовойКолонки, "Новая колонка");
КолонкаТП.Данные = ИмяНовойКолонки; // связываем колонку с полем источника
КолонкаТП.УстановитьЭлементУправления(Тип("ПолеВвода"));
При таком способе существующие колонки остаются на своих местах, их пользовательский и программный порядок сохраняется, а новая колонка корректно отображается в форме.
Если требуется перемещать колонки, логику упорядочивания необходимо применять непосредственно к источнику данных (ТаблицаЗначений), а не только к представлению на форме. Коллекция колонок таблицы значений поддерживает метод Сдвинуть().
Разберем по шагам, как определить текущую колонку в табличном поле и сдвинуть её в самой таблице значений:
ТекущаяКолонкаТП = ЭлементыФормы.ТабПоле.ТекущаяКолонка;
Если ТекущаяКолонкаТП <> Неопределено И Не ПустаяСтрока(ТекущаяКолонкаТП.Данные) Тогда
// Находим колонку в ТаблицеЗначений по имени поля данных
КолонкаТЗ = ТЗ.Колонки.Найти(ТекущаяКолонкаТП.Данные);
Если КолонкаТЗ <> Неопределено Тогда
// Сдвигаем колонку в источнике данных (например, на 1 позицию вправо)
ТЗ.Колонки.Сдвинуть(КолонкаТЗ, 1);
// Синхронно сдвигаем в табличном поле для визуального отображения
ЭлементыФормы.ТабПоле.Колонки.Сдвинуть(ТекущаяКолонкаТП, 1);
КонецЕсли;
КонецЕсли;
Синхронизируя порядок в объекте ТаблицаЗначений, мы гарантируем, что даже в случае полного пересоздания колонок их очередность останется актуальной.
Если состав колонок заранее известен или формируется по сложному алгоритму, рекомендуется сначала полностью сконфигурировать коллекцию колонок в ТаблицаЗначений, применить все сортировки и сдвиги, и только в самом конце однократно вызвать метод СоздатьКолонки().
// Формируем структуру источника полностью
ТЗ.Колонки.Очистить();
ТЗ.Колонки.Добавить("Код", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(9)), "Код");
ТЗ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "Номенклатура");
ТЗ.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(10, 3)), "Количество");
// Перемещаем нужную колонку в источнике
ТЗ.Колонки.Сдвинуть(ТЗ.Колонки.Количество, -1);
// Инициализируем визуальное отображение один раз
ЭлементыФормы.ТабПоле.Значение = ТЗ;
ЭлементыФормы.ТабПоле.СоздатьКолонки();
В управляемом интерфейсе модель работы с динамическими таблицами принципиально отличается. Для динамического управления реквизитами формы и элементами интерфейса применяются следующие правила:
ИзменитьРеквизиты().Элементы.Добавить("ИмяЭлемента", Тип("ПолеФормы"), Элементы.ИмяТаблицы).Элементы.Переместить(Элемент, Родитель, ЭлементПередКоторымВставить).