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

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

Как получить индекс текущей строки в 1С

Способы получить индекс текущей строки в 1С: ТекущиеДанные формы, метод Индекс(), перебор коллекций. Разбор разницы между индексом и номером строки, примеры кода, ошибки.

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

Ключевой момент: в 1С индексация коллекций начинается с нуля, а свойство НомерСтроки табличной части начинается с единицы. Если вы смешаете эти значения, получите смещение на одну позицию и обращение не к той строке. Ниже разобраны все рабочие способы с примерами кода для управляемых и обычных форм.

Чем индекс отличается от номера строки и идентификатора

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

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

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

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

Самый частый сценарий — узнать, на какой строке табличной части стоит пользователь. В модуле формы это делается через элемент формы, а не через объект данных:

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

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

Возврат; // курсор не установлен ни на одну строку

КонецЕсли;

НомерТекущейСтроки = ТекСтрока.НомерСтроки;

Обратите внимание: ТекущиеДанные доступно только на клиенте в контексте формы. Если обработчик объявлен с директивой &НаСервере, обратиться к нему напрямую не получится — нужно либо передавать номер строки параметром, либо работать через реквизит формы Объект.

Если нужен именно индекс (позиция с нуля), его вычисляют от коллекции:

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

// ИндексСтроки = ТекСтрока.НомерСтроки - 1 — тот же результат

Индекс строки при переборе коллекции в коде

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

// Вариант 1: цикл по индексам

Для Инд = 0 По Объект.Товары.Количество() - 1 Цикл

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

// Инд — индекс текущей строки (с нуля)

КонецЦикла;

// Вариант 2: цикл Для Каждого + метод Индекс()

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

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

КонецЦикла;

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

Таблица значений на сервере

Для таблицы значений логика та же: ТЗ.Индекс(СтрокаТЗ) вернёт позицию с нуля. Если в таблице значений нужен «человеческий» номер строки, добавьте колонку и заполните её при формировании таблицы — платформа это за вас не сделает.

bsl
ТЗ.Колонки.Добавить("НомерСтроки");
Для Инд = 0 По ТЗ.Количество() - 1 Цикл
    ТЗ[Инд].НомерСтроки = Инд + 1;
КонецЦикла;

Текущая строка в динамическом списке и обычных формах

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

В обычных формах (толстый клиент, режим обычного приложения) механика похожа: у табличного поля есть свойство ТекущиеДанные, а индекс вычисляется методом Индекс() от источника данных. Дополнительно доступно ЭлементыФормы.Товары.ТекущаяСтрока, которое для табличной части возвращает саму строку.

Сравнение вариантов

НомерСтроки

Подходит для сообщений пользователю и поиска строки в табличной части. Начинается с 1, недоступен у таблиц значений и динамических списков.

Индекс(Строка)

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

Счётчик цикла

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

ТекущаяСтрока таблицы формы

Даёт идентификатор строки данных формы или ссылку для динамического списка. Это не порядковый номер — для нумерации не подходит.

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

Первая ошибка — смешение индекса и номера строки. Код Объект.Товары[ТекСтрока.НомерСтроки] обратится к следующей строке, а для последней строки вызовет выход за границы коллекции. Правильно: Объект.Товары[ТекСтрока.НомерСтроки - 1], хотя надёжнее вообще работать с самим объектом строки, а не с позицией.

Вторая ошибка — обращение к ТекущиеДанные на сервере. Компилятор модуля это не отловит, ошибка проявится только в runtime. Если логика серверная, передавайте в серверную процедуру номер строки или идентификатор параметром из клиентского обработчика.

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

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

Проверка результата

Проверить корректность полученного индекса проще всего отладчиком: поставьте точку останова в обработчике, встаньте курсором на известную строку (например, вторую) и сравните значения ТекущиеДанные.НомерСтроки и Индекс(). Для второй строки должно быть: НомерСтроки = 2, индекс = 1.

Быстрый способ без отладчика — вывести значения в сообщение:

Сообщить("Номер: " + ТекСтрока.НомерСтроки

+ ", индекс: " + Объект.Товары.Индекс(ТекСтрока));

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

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

Соответствие индекса и номера
Норма

Индекс = НомерСтроки - 1 для той же строки

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

Значения совпадают или различаются больше чем на 1 — перепутаны коллекции

Поведение на пустой таблице
Норма

ТекущиеДанные = Неопределено, код завершается без ошибки

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

Ошибка обращения к полям строки

Работа после удаления строк
Норма

Номера строк пересчитаны платформой, позиции корректны

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

Используется сохранённый ранее номер — указывает не на ту строку

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

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

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

Почему Индекс() возвращает -1?

Метод Индекс() возвращает -1, если переданная строка не принадлежит коллекции, у которой вызван метод. Это бывает, когда строка получена из другой табличной части, из копии таблицы или из выборки, а не из самой коллекции.

Можно ли получить индекс текущей строки динамического списка?

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

Как передать номер строки в серверную процедуру?

В клиентском обработчике получите номер через ТекущиеДанные.НомерСтроки и передайте его параметром в серверную процедуру. На сервере обратитесь к строке как Объект.Товары[НомерСтроки - 1].

Чем заменить Индекс() в большом цикле?

Используйте цикл Для со счётчиком от 0 до Количество() - 1 — позиция строки будет равна счётчику без дополнительного поиска по коллекции. Это заметно быстрее на табличных частях с сотнями и тысячами строк.

Есть ли номер строки у таблицы значений?

Штатного свойства НомерСтроки у строк таблицы значений нет. При необходимости добавьте числовую колонку и заполните её в цикле значением Инд + 1.

Итог

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

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