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

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

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

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

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

Ключевой принцип: перебирать нужно не строки элемента формы, а строки коллекции данных, с которой этот элемент связан. В управляемой форме это коллекция типа ДанныеФормыКоллекция, в обычной — ТабличнаяЧасть или ТаблицаЗначений. Обращение напрямую к элементу формы требуется только для работы с выделенными строками или текущей строкой.

Ниже разобраны рабочие варианты перебора для управляемых и обычных форм, обход выделенных строк, изменение данных во время цикла и типичные ошибки, которые приводят к потере строк или падению производительности.

Что перебирать: данные, а не элемент формы

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

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

Перебор табличной части в управляемой форме

Базовый сценарий: на форме документа есть табличная часть «Товары», нужно обойти все строки и, например, пересчитать сумму. Обращение идёт через свойство Объект:

&НаКлиенте

Процедура ПересчитатьСуммы(Команда)

Для Каждого Строка Из Объект.Товары Цикл

Строка.Сумма = Строка.Количество * Строка.Цена;

КонецЦикла;

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

Цикл «Для Каждого» перебирает строки в том порядке, в котором они идут в коллекции. Если нужен доступ по индексу (например, для сравнения соседних строк), используйте цикл со счётчиком: индексация коллекции начинается с нуля, а количество строк возвращает метод Количество().

КоличествоСтрок = Объект.Товары.Количество();

Для Индекс = 0 По КоличествоСтрок - 1 Цикл

Строка = Объект.Товары[Индекс];

// работа со строкой

КонецЦикла;

Если обработка длительная или требует вызова сервера, перебор лучше выполнять в серверной процедуре: передавать всю коллекцию на сервер по одной строке дорого, а обход целиком на сервере выполняется заметно быстрее.

Перебор реквизита формы типа «Таблица значений»

Когда таблица на форме не связана с объектом, а добавлена как реквизит формы (например, «РезультатПодбора»), обход выглядит аналогично — коллекция доступна по имени реквизита напрямую:

&НаКлиенте

Процедура ОбработатьРезультат(Команда)

Для Каждого Строка Из РезультатПодбора Цикл

Если Строка.Пометка Тогда

// обработка отмеченной строки

КонецЕсли;

КонецЦикла;

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

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

Отбор = Новый Структура("Номенклатура", ИскомаяНоменклатура);

Найденные = Объект.Товары.НайтиСтроки(Отбор);

Для Каждого Строка Из Найденные Цикл

Строка.Количество = Строка.Количество + 1;

КонецЦикла;

Обход только выделенных строк

Частая задача — обработать только те строки, которые пользователь выделил мышью. Здесь как раз нужен элемент формы: метод Элементы.ИмяТаблицы.ВыделенныеСтроки возвращает массив идентификаторов строк, а сами строки получают через НайтиПоИдентификатору:

&НаКлиенте

Процедура ОбработатьВыделенные(Команда)

Для Каждого Идентификатор Из Элементы.Товары.ВыделенныеСтроки Цикл

Строка = Объект.Товары.НайтиПоИдентификатору(Идентификатор);

Если Строка <> Неопределено Тогда

Строка.Пометка = Истина;

КонецЕсли;

КонецЦикла;

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

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

Порядок действий при обходе выделенных строк
  1. 1
    Получите массив идентификаторов: Элементы.ИмяТаблицы.ВыделенныеСтроки
  2. 2
    В цикле найдите каждую строку: Коллекция.НайтиПоИдентификатору(Идентификатор)
  3. 3
    Проверьте, что строка найдена (не равна Неопределено)
  4. 4
    Выполните нужные изменения данных строки
  5. 5
    После массовых изменений при необходимости вызовите Модифицированность = Истина

Перебор в обычных формах (8.2, толстый клиент)

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

Для Каждого Строка Из Товары Цикл

// Товары — табличная часть документа

КонецЦикла;

Для Каждого Строка Из ТаблицаДанных Цикл

// ТаблицаДанных — реквизит формы типа ТаблицаЗначений

КонецЦикла;

Выделенные строки в обычном приложении получают через ЭлементыФормы.ИмяТаблицы.ВыделенныеСтроки — там это сразу коллекция строк, а не идентификаторов, поэтому НайтиПоИдентификатору не нужен. Это принципиальное отличие, из-за которого код из обычной формы нельзя перенести в управляемую без доработки.

Изменение и удаление строк во время перебора

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

КоличествоСтрок = Объект.Товары.Количество();

Для Индекс = 1 По КоличествоСтрок Цикл

Строка = Объект.Товары[КоличествоСтрок - Индекс];

Если Строка.Количество = 0 Тогда

Объект.Товары.Удалить(Строка);

КонецЕсли;

КонецЦикла;

Альтернатива — сначала собрать строки-кандидаты в отдельный массив, а затем удалить их после завершения цикла обхода. Оба подхода корректны; обратный обход короче, сбор в массив нагляднее при сложных условиях.

Типичные ошибки
01
Попытка обратиться к Элементы.Товары.Строки — у элемента формы нет такого свойства, нужна коллекция данных
02
Удаление строк в прямом цикле «Для Каждого» — часть строк пропускается, удаляйте в обратном порядке по индексу
03
Использование ТекущаяСтрока как объекта данных — это идентификатор, строку нужно получить через НайтиПоИдентификатору
04
Перебор динамического списка как коллекции — список подгружает данные порциями, все строки так не получить
05
Вызов сервера на каждую строку в клиентском цикле — сотни серверных вызовов резко замедляют работу

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

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

По производительности: перебор коллекции из нескольких тысяч строк на клиенте занимает доли секунды, проблемы начинаются при серверных вызовах внутри цикла и при обращении через точку к данным ссылки (Объект.Товары[0].Номенклатура.Артикул — это обращение к базе на каждой строке). Лучше один раз выгрузить нужные реквизиты запросом в соответствие и читать из него.

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

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

Количество обработанных строк
Норма

Совпадает с Количество() коллекции или числом выделенных строк

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

Меньше ожидаемого — вероятно, удаление в прямом цикле

Отображение изменений в таблице
Норма

Новые значения видны сразу после выполнения процедуры

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

Данные изменились, но таблица не обновилась — проверьте связь элемента с данными

Флаг модифицированности
Норма

После изменений форма предлагает сохранить объект

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

Изменения есть, форма закрывается без вопроса — данные потеряются

Итог

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

Перебирайте коллекцию данных (Объект.ТабличнаяЧасть или реквизит формы), а не элемент формы. Выделенные строки — через Элементы.Имя.ВыделенныеСтроки и НайтиПоИдентификатору. Удаляйте строки в обратном порядке по индексу. Тяжёлую обработку выносите на сервер одним вызовом.

Частые вопросы

Как узнать номер текущей строки табличного поля?

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

Можно ли перебрать строки динамического списка циклом?

Нет, динамический список не хранит все строки на клиенте. Для обхода его данных выполните запрос с тем же текстом и отборами или используйте СхемуКомпоновкиДанных списка с программным выводом в таблицу значений.

Почему в цикле «Для Каждого» пропускаются строки при удалении?

При удалении текущего элемента индексы остальных смещаются, и итератор переходит к следующей позиции, пропуская сдвинувшуюся строку. Удаляйте в обратном цикле по индексу или собирайте строки для удаления в отдельный массив.

Как перебрать строки и сразу открыть их для редактирования?

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

Работает ли перебор в веб-клиенте?

Да, циклы по коллекциям данных формы работают в веб-клиенте так же, как в тонком. Ограничения касаются только операций с файловой системой и COM-объектами, к перебору строк они отношения не имеют.