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