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