Разработка и Конфигурация · 10 мин
Как программно переместить строку табличной части в 1С
Способы программного перемещения строки табличной части в 1С: метод Сдвинуть, перестановка строк в форме, работа с ТаблицаЗначений. Примеры кода и типичные ошибки.
Перемещение строки табличной части — типовая задача при разработке и доработке конфигураций 1С:Предприятие 8. Она возникает при реализации сортировки товаров по приоритету, изменении порядка этапов в документе, перестановке записей после обмена данными или при построении собственных механизмов «вверх/вниз» на форме. В зависимости от того, где находятся данные — в табличной части объекта, в таблице значений или в динамическом списке, применяются разные методы, и у каждого есть свои ограничения.
Ключевой момент, который нужно понимать сразу: у табличной части объекта нет встроенного метода «переместить» в привычном смысле. Для коллекции строк табличной части доступен метод Сдвинуть(), а для таблицы значений — аналогичный метод с тем же названием. Кроме того, существует программная перестановка через индексы и обход с временным хранением данных строки. Ниже разобраны все рабочие сценарии с примерами кода.
Метод Сдвинуть — основной способ перемещения строки
Метод Сдвинуть() есть у коллекции строк табличной части и у таблицы значений. Он принимает два параметра: строку (или её индекс) и величину смещения. Положительное смещение двигает строку вниз по списку, отрицательное — вверх. Если смещение выходит за границы коллекции, строка просто окажется в начале или в конце, исключения не возникнет.
Типовой пример для табличной части документа на сервере:
&НаСервере
Процедура СдвинутьСтрокуВверхНаСервере(НомерСтроки)
ДокументОбъект = РеквизитФормыВЗначение("Объект");
ТЧ = ДокументОбъект.Товары;
Индекс = НомерСтроки - 1; // нумерация в коллекции с нуля
Если Индекс > 0 Тогда
ТЧ.Сдвинуть(Индекс, -1);
КонецЕсли;
ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");
КонецПроцедуры
Обратите внимание на пересчёт номера строки в индекс: пользователь видит нумерацию с единицы, а коллекция индексируется с нуля. Это самая частая причина «съехавшего» перемещения. Также учитывайте, что метод Сдвинуть() принимает как индекс, так и саму строку — оба варианта корректны.
Перемещение строки в форме через ДанныеФормыКоллекция
Если строку нужно переместить непосредственно в реквизите формы без обращения к объекту, работайте с коллекцией формы напрямую. У реквизита типа «ДанныеФормыКоллекция» (например, Объект.Товары в управляемой форме) метод Сдвинуть() также доступен, и это самый быстрый способ без серверного вызова с преобразованием объекта.
Пример клиентской процедуры для кнопок «Вверх» и «Вниз»:
&НаКлиенте
Процедура ПереместитьВверх(Команда)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
Индекс = Объект.Товары.Индекс(ТекущиеДанные);
Если Индекс > 0 Тогда
Объект.Товары.Сдвинуть(Индекс, -1);
КонецЕсли;
КонецПроцедуры
Такой вариант хорош тем, что не требует контекстного серверного вызова и работает мгновенно даже на больших табличных частях. После сдвига форма автоматически отображает новый порядок, дополнительное обновление не нужно.
- 1Добавьте на форму команды ПереместитьВверх и ПереместитьВниз
- 2Получите текущую строку через Элементы.Товары.ТекущиеДанные
- 3Найдите её индекс методом Индекс() коллекции
- 4Вызовите Сдвинуть(Индекс, -1) для движения вверх или Сдвинуть(Индекс, 1) для движения вниз
- 5Проверьте границы: не двигать первую строку вверх и последнюю вниз
- 6Убедитесь, что форма отобразила новый порядок строк
Перестановка двух строк по индексам
Иногда требуется не сдвиг, а обмен местами двух конкретных строк — например, при реализации сортировки «пузырьком» по собственному правилу. Прямого метода «поменять местами» нет, поэтому данные копируют во временную структуру или используют два сдвига.
Надёжный вариант — скопировать значения полей одной строки во временную структуру, затем перезаписать строки через ЗаполнитьЗначенияСвойств():
Процедура ПоменятьСтрокиМестами(ТЧ, Индекс1, Индекс2)
Строка1 = ТЧ[Индекс1];
Строка2 = ТЧ[Индекс2];
Временная = Новый Структура;
Для Каждого Колонка Из ТЧ.Выгрузить().Колонки Цикл
Временная.Вставить(Колонка.Имя);
КонецЦикла;
ЗаполнитьЗначенияСвойств(Временная, Строка1);
ЗаполнитьЗначенияСвойств(Строка1, Строка2);
ЗаполнитьЗначенияСвойств(Строка2, Временная);
КонецПроцедуры
Альтернатива — два вызова Сдвинуть(): сначала одну строку к позиции другой, затем вторую на освободившееся место. Это короче, но требует аккуратного расчёта смещений, особенно когда строки находятся далеко друг от друга.
Перемещение строки в таблице значений
Таблица значений — частый промежуточный формат: данные выгружаются из табличной части, обрабатываются и загружаются обратно. У таблицы значений метод Сдвинуть() работает так же, как у табличной части, что упрощает перенос логики.
ТЗ = ДокументОбъект.Товары.Выгрузить();
// Переместить первую строку в конец
ТЗ.Сдвинуть(0, ТЗ.Количество() - 1);
ДокументОбъект.Товары.Загрузить(ТЗ);
Если требуется полностью переупорядочить строки по произвольному правилу, часто проще не двигать строки по одной, а отсортировать таблицу методом Сортировать() по служебной колонке порядка, а затем загрузить результат обратно. Это существенно быстрее при большом числе строк, так как каждый сдвиг в коллекции — операция перестройки порядка.
Сравнение подходов
Подходит для интерактивных кнопок Вверх/Вниз; не требует серверного вызова, но двигает только на заданное смещение
Подходит для обработок и проведения; требует преобразования реквизита формы в объект
Оптимально для массового переупорядочивания; требует служебной колонки и загрузки обратно
Подходит для точечной перестановки двух строк; избыточен для массовых операций
Динамический список: почему Сдвинуть не работает и что делать
Динамический список — это не коллекция строк, а результат запроса, поэтому методов Сдвинуть() или Индекс() у него нет. Стандартное интерактивное перемещение доступно только для списков с основной таблицей и без произвольного запроса, и то — в пределах стандартного порядка.
Если нужен управляемый порядок элементов в динамическом списке (например, ручная расстановка этапов маршрута), внедряют служебное числовое поле «Порядок» в сам объект данных. Кнопки «вверх/вниз» пересчитывают значения этого поля у соседних элементов, а список сортируется по нему. Это единственный устойчивый способ, потому что порядок хранится в базе, а не в представлении.
Типичные ошибки и проверка результата
Первая частая ошибка — путаница между номером строки (начинается с 1) и индексом коллекции (начинается с 0). Вторая — попытка сдвинуть строку в динамическом списке или в дереве значений через методы табличной части. Третья — перемещение строки в объекте, полученном через РеквизитФормыВЗначение(), без обратного вызова ЗначениеВРеквизитФормы(): на форме ничего не изменится, и разработчик долго ищет «пропавший» сдвиг.
Ещё одна проблема — работа с текущей строкой после сдвига. Курсор таблицы формы может остаться на прежней позиции, и пользователю покажется, что переместилась «не та» строка. После сдвига имеет смысл программно установить текущую строку через Элементы.Товары.ТекущаяСтрока.
Проверить результат просто: после операции выведите порядок ключевых полей строк (например, номенклатуру и количество) до и после сдвига или проконтролируйте визуально на форме. Для серверных обработок полезен контроль через Индекс(): индекс перемещённой строки должен измениться ровно на величину смещения.
Как проверить результат
Индекс изменился ровно на величину смещения
Строка осталась на месте или сдвинулась не туда
Порядок строк визуально совпадает с ожидаемым
Форма показывает старый порядок — забыли ЗначениеВРеквизитФормы
После записи документа порядок строк сохраняется
После перезаписи порядок сбрасывается — изменения не записаны
FAQ
Можно ли переместить строку табличной части на несколько позиций сразу?
Да. Параметр смещения метода Сдвинуть() принимает любое целое число: Сдвинуть(Индекс, 5) переместит строку на пять позиций вниз. Если смещение выходит за границы коллекции, строка окажется в конце или начале без ошибки.
Как переместить строку в самое начало или в конец табличной части?
Вызовите Сдвинуть с максимальным смещением: для перемещения в начало — Сдвинуть(Индекс, -Индекс), в конец — Сдвинуть(Индекс, Коллекция.Количество() - 1 - Индекс). Можно также просто передать смещение с запасом, например -1000000, строка гарантированно окажется первой.
Почему после Сдвинуть на сервере на форме ничего не изменилось?
Вы работали с копией объекта, полученной через РеквизитФормыВЗначение(), и не вернули её в форму. Добавьте вызов ЗначениеВРеквизитФормы(ДокументОбъект, "Объект") после изменений, и порядок строк на форме обновится.
Как переместить строку в дереве значений?
У строк дерева значений метод Сдвинуть не применяется напрямую к уровню иерархии, но доступен у коллекции строк одного родителя: Родитель.Строки.Сдвинуть(Индекс, -1). При переносе между уровнями строку нужно добавить к новому родителю, скопировать данные и удалить из старого.
Влияет ли порядок строк табличной части на проведение документа?
В типовых документах обычно нет, но в доработанных алгоритмах порядок может иметь значение, например при списании партий или распределении сумм. Перед изменением порядка в проведённых документах проверьте модуль проведения конкретного вида документов.
Как сделать перемещение строк перетаскиванием мышью?
В управляемой форме включите у таблицы свойство «РазрешитьПеретаскивание» и обработайте событие «Перетаскивание»: внутри определите целевую позицию и выполните Сдвинуть() программно. Стандартное перетаскивание само по себе порядок в коллекции не меняет без обработчика.
Что важно запомнить
Основной инструмент перемещения строки — метод Сдвинуть(Индекс, Смещение), доступный у табличной части, таблицы значений и коллекции формы. Помните о нумерации индексов с нуля, возвращайте изменённый объект в форму и не применяйте метод к динамическому списку — там порядок задаётся служебным полем и сортировкой.