К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как программно переместить строку табличной части в 1С

Способы программного перемещения строки табличной части в 1С: метод Сдвинуть, перестановка строк в форме, работа с ТаблицаЗначений. Примеры кода и типичные ошибки.

Перемещение строки табличной части — типовая задача при разработке и доработке конфигураций 1С:Предприятие 8. Она возникает при реализации сортировки товаров по приоритету, изменении порядка этапов в документе, перестановке записей после обмена данными или при построении собственных механизмов «вверх/вниз» на форме. В зависимости от того, где находятся данные — в табличной части объекта, в таблице значений или в динамическом списке, применяются разные методы, и у каждого есть свои ограничения.

Ключевой момент, который нужно понимать сразу: у табличной части объекта нет встроенного метода «переместить» в привычном смысле. Для коллекции строк табличной части доступен метод Сдвинуть(), а для таблицы значений — аналогичный метод с тем же названием. Кроме того, существует программная перестановка через индексы и обход с временным хранением данных строки. Ниже разобраны все рабочие сценарии с примерами кода.

Метод Сдвинуть — основной способ перемещения строки

Метод Сдвинуть() есть у коллекции строк табличной части и у таблицы значений. Он принимает два параметра: строку (или её индекс) и величину смещения. Положительное смещение двигает строку вниз по списку, отрицательное — вверх. Если смещение выходит за границы коллекции, строка просто окажется в начале или в конце, исключения не возникнет.

Типовой пример для табличной части документа на сервере:

&НаСервере

Процедура СдвинутьСтрокуВверхНаСервере(НомерСтроки)

ДокументОбъект = РеквизитФормыВЗначение("Объект");

ТЧ = ДокументОбъект.Товары;

Индекс = НомерСтроки - 1; // нумерация в коллекции с нуля

Если Индекс > 0 Тогда

ТЧ.Сдвинуть(Индекс, -1);

КонецЕсли;

ЗначениеВРеквизитФормы(ДокументОбъект, "Объект");

КонецПроцедуры

Обратите внимание на пересчёт номера строки в индекс: пользователь видит нумерацию с единицы, а коллекция индексируется с нуля. Это самая частая причина «съехавшего» перемещения. Также учитывайте, что метод Сдвинуть() принимает как индекс, так и саму строку — оба варианта корректны.

Перемещение строки в форме через ДанныеФормыКоллекция

Если строку нужно переместить непосредственно в реквизите формы без обращения к объекту, работайте с коллекцией формы напрямую. У реквизита типа «ДанныеФормыКоллекция» (например, Объект.Товары в управляемой форме) метод Сдвинуть() также доступен, и это самый быстрый способ без серверного вызова с преобразованием объекта.

Пример клиентской процедуры для кнопок «Вверх» и «Вниз»:

&НаКлиенте

Процедура ПереместитьВверх(Команда)

ТекущиеДанные = Элементы.Товары.ТекущиеДанные;

Если ТекущиеДанные = Неопределено Тогда

Возврат;

КонецЕсли;

Индекс = Объект.Товары.Индекс(ТекущиеДанные);

Если Индекс > 0 Тогда

Объект.Товары.Сдвинуть(Индекс, -1);

КонецЕсли;

КонецПроцедуры

Такой вариант хорош тем, что не требует контекстного серверного вызова и работает мгновенно даже на больших табличных частях. После сдвига форма автоматически отображает новый порядок, дополнительное обновление не нужно.

Порядок действий для кнопок «Вверх/Вниз»
  1. 1
    Добавьте на форму команды ПереместитьВверх и ПереместитьВниз
  2. 2
    Получите текущую строку через Элементы.Товары.ТекущиеДанные
  3. 3
    Найдите её индекс методом Индекс() коллекции
  4. 4
    Вызовите Сдвинуть(Индекс, -1) для движения вверх или Сдвинуть(Индекс, 1) для движения вниз
  5. 5
    Проверьте границы: не двигать первую строку вверх и последнюю вниз
  6. 6
    Убедитесь, что форма отобразила новый порядок строк

Перестановка двух строк по индексам

Иногда требуется не сдвиг, а обмен местами двух конкретных строк — например, при реализации сортировки «пузырьком» по собственному правилу. Прямого метода «поменять местами» нет, поэтому данные копируют во временную структуру или используют два сдвига.

Надёжный вариант — скопировать значения полей одной строки во временную структуру, затем перезаписать строки через ЗаполнитьЗначенияСвойств():

Процедура ПоменятьСтрокиМестами(ТЧ, Индекс1, Индекс2)

Строка1 = ТЧ[Индекс1];

Строка2 = ТЧ[Индекс2];

Временная = Новый Структура;

Для Каждого Колонка Из ТЧ.Выгрузить().Колонки Цикл

Временная.Вставить(Колонка.Имя);

КонецЦикла;

ЗаполнитьЗначенияСвойств(Временная, Строка1);

ЗаполнитьЗначенияСвойств(Строка1, Строка2);

ЗаполнитьЗначенияСвойств(Строка2, Временная);

КонецПроцедуры

Альтернатива — два вызова Сдвинуть(): сначала одну строку к позиции другой, затем вторую на освободившееся место. Это короче, но требует аккуратного расчёта смещений, особенно когда строки находятся далеко друг от друга.

Перемещение строки в таблице значений

Таблица значений — частый промежуточный формат: данные выгружаются из табличной части, обрабатываются и загружаются обратно. У таблицы значений метод Сдвинуть() работает так же, как у табличной части, что упрощает перенос логики.

ТЗ = ДокументОбъект.Товары.Выгрузить();

// Переместить первую строку в конец

ТЗ.Сдвинуть(0, ТЗ.Количество() - 1);

ДокументОбъект.Товары.Загрузить(ТЗ);

Если требуется полностью переупорядочить строки по произвольному правилу, часто проще не двигать строки по одной, а отсортировать таблицу методом Сортировать() по служебной колонке порядка, а затем загрузить результат обратно. Это существенно быстрее при большом числе строк, так как каждый сдвиг в коллекции — операция перестройки порядка.

Сравнение подходов

Сдвинуть() в форме

Подходит для интерактивных кнопок Вверх/Вниз; не требует серверного вызова, но двигает только на заданное смещение

Сдвинуть() в объекте на сервере

Подходит для обработок и проведения; требует преобразования реквизита формы в объект

Сортировка ТЗ по колонке порядка

Оптимально для массового переупорядочивания; требует служебной колонки и загрузки обратно

Обмен значений через структуру

Подходит для точечной перестановки двух строк; избыточен для массовых операций

Динамический список: почему Сдвинуть не работает и что делать

Динамический список — это не коллекция строк, а результат запроса, поэтому методов Сдвинуть() или Индекс() у него нет. Стандартное интерактивное перемещение доступно только для списков с основной таблицей и без произвольного запроса, и то — в пределах стандартного порядка.

Если нужен управляемый порядок элементов в динамическом списке (например, ручная расстановка этапов маршрута), внедряют служебное числовое поле «Порядок» в сам объект данных. Кнопки «вверх/вниз» пересчитывают значения этого поля у соседних элементов, а список сортируется по нему. Это единственный устойчивый способ, потому что порядок хранится в базе, а не в представлении.

Типичные ошибки и проверка результата

Первая частая ошибка — путаница между номером строки (начинается с 1) и индексом коллекции (начинается с 0). Вторая — попытка сдвинуть строку в динамическом списке или в дереве значений через методы табличной части. Третья — перемещение строки в объекте, полученном через РеквизитФормыВЗначение(), без обратного вызова ЗначениеВРеквизитФормы(): на форме ничего не изменится, и разработчик долго ищет «пропавший» сдвиг.

Ещё одна проблема — работа с текущей строкой после сдвига. Курсор таблицы формы может остаться на прежней позиции, и пользователю покажется, что переместилась «не та» строка. После сдвига имеет смысл программно установить текущую строку через Элементы.Товары.ТекущаяСтрока.

Типичные ошибки
01
Передача номера строки вместо индекса — сдвигается соседняя строка
02
Сдвиг в объекте без ЗначениеВРеквизитФормы — форма не обновляется
03
Попытка применить Сдвинуть к динамическому списку — ошибка исполнения
04
Отсутствие проверки границ — лишние вызовы при первой и последней строке
05
Массовое перемещение по одной строке вместо сортировки — медленная работа на больших таблицах

Проверить результат просто: после операции выведите порядок ключевых полей строк (например, номенклатуру и количество) до и после сдвига или проконтролируйте визуально на форме. Для серверных обработок полезен контроль через Индекс(): индекс перемещённой строки должен измениться ровно на величину смещения.

Контрольные точки

Как проверить результат

Позиция строки после сдвига
Норма

Индекс изменился ровно на величину смещения

Тревожный признак

Строка осталась на месте или сдвинулась не туда

Отображение на форме
Норма

Порядок строк визуально совпадает с ожидаемым

Тревожный признак

Форма показывает старый порядок — забыли ЗначениеВРеквизитФормы

Сохранение данных
Норма

После записи документа порядок строк сохраняется

Тревожный признак

После перезаписи порядок сбрасывается — изменения не записаны

FAQ

Можно ли переместить строку табличной части на несколько позиций сразу?

Да. Параметр смещения метода Сдвинуть() принимает любое целое число: Сдвинуть(Индекс, 5) переместит строку на пять позиций вниз. Если смещение выходит за границы коллекции, строка окажется в конце или начале без ошибки.

Как переместить строку в самое начало или в конец табличной части?

Вызовите Сдвинуть с максимальным смещением: для перемещения в начало — Сдвинуть(Индекс, -Индекс), в конец — Сдвинуть(Индекс, Коллекция.Количество() - 1 - Индекс). Можно также просто передать смещение с запасом, например -1000000, строка гарантированно окажется первой.

Почему после Сдвинуть на сервере на форме ничего не изменилось?

Вы работали с копией объекта, полученной через РеквизитФормыВЗначение(), и не вернули её в форму. Добавьте вызов ЗначениеВРеквизитФормы(ДокументОбъект, "Объект") после изменений, и порядок строк на форме обновится.

Как переместить строку в дереве значений?

У строк дерева значений метод Сдвинуть не применяется напрямую к уровню иерархии, но доступен у коллекции строк одного родителя: Родитель.Строки.Сдвинуть(Индекс, -1). При переносе между уровнями строку нужно добавить к новому родителю, скопировать данные и удалить из старого.

Влияет ли порядок строк табличной части на проведение документа?

В типовых документах обычно нет, но в доработанных алгоритмах порядок может иметь значение, например при списании партий или распределении сумм. Перед изменением порядка в проведённых документах проверьте модуль проведения конкретного вида документов.

Как сделать перемещение строк перетаскиванием мышью?

В управляемой форме включите у таблицы свойство «РазрешитьПеретаскивание» и обработайте событие «Перетаскивание»: внутри определите целевую позицию и выполните Сдвинуть() программно. Стандартное перетаскивание само по себе порядок в коллекции не меняет без обработчика.

Итог

Что важно запомнить

Основной инструмент перемещения строки — метод Сдвинуть(Индекс, Смещение), доступный у табличной части, таблицы значений и коллекции формы. Помните о нумерации индексов с нуля, возвращайте изменённый объект в форму и не применяйте метод к динамическому списку — там порядок задаётся служебным полем и сортировкой.