Почему при работе с текущей строкой табличной части в 1С возникает ошибка 'Индекс находится за границами массива' и как это исправить?

Программист 1С v8.3 (Управляемые формы) 1С:Розница Торговля и дистрибуция
← На главную

Работая с платформами 1С, многие разработчики сталкиваются с, казалось бы, простой задачей — получить данные текущей строки табличной части. Однако, попытка напрямую использовать свойство ТекущаяСтрока табличного поля может привести к неожиданной и неприятной ошибке: "Индекс находится за границами массива". Давайте вместе разберемся, почему так происходит, и как правильно работать с текущей строкой табличной части, чтобы избежать этой ошибки.

Выясняем причину: Что такое ТекущаяСтрока на самом деле?

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

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

Почему возникает ошибка "Индекс находится за границами массива"?

Проблема возникает, когда мы пытаемся использовать этот уникальный идентификатор строки формы как прямой числовой индекс для обращения к коллекции строк табличной части объекта. Например, если мы пишем что-то вроде Объект.Товары[ТекСтрокаИдентификатор], где ТекСтрокаИдентификатор — это значение, полученное из Элементы.Товары.ТекущаяСтрока.

Коллекция строк табличной части самого объекта (например, Объект.Товары) имеет свои собственные числовые индексы, которые начинаются с 0 и увеличиваются последовательно. При любых изменениях в табличной части — добавлении новых строк, удалении существующих или изменении их порядка — эти числовые индексы пересчитываются. Старый идентификатор строки формы, который мы ошибочно пытаемся использовать как индекс, с большой вероятностью не будет соответствовать правильному числовому индексу в текущей коллекции. Это приводит к попытке обратиться к несуществующему элементу по индексу, и как следствие, мы получаем ошибку "Индекс находится за границами массива".

Правильный подход: Используем метод НайтиПоИдентификатору()

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

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

Давайте посмотрим на пример, который демонстрирует этот подход:


// Шаг 1: Получаем уникальный идентификатор текущей строки из табличного поля на форме
ТекСтрокаИдентификатор = Элементы.Товары.ТекущаяСтрока;

// Шаг 2: Используем метод НайтиПоИдентификатору() для поиска объекта строки данных
// в коллекции табличной части объекта по полученному идентификатору
ТекущиеДанные = Объект.Товары.НайтиПоИдентификатору(ТекСтрокаИдентификатор);

// Шаг 3: Теперь мы можем безопасно работать с найденным объектом строки
// Например, изменить его реквизиты
Если ТекущиеДанные <> Неопределено Тогда
    ТекущиеДанные.Продавец = СтрокаРезультата.ВладелецКарты;
Иначе
    Сообщить("Не удалось найти текущую строку в табличной части.");
КонецЕсли;

В этом примере ТекущиеДанные будет содержать корректный объект строки табличной части (например, типа СтрокаТабличнойЧастиДокументаОбъект.Товары), с которым мы можем безопасно работать, обращаясь к его реквизитам. Метод НайтиПоИдентификатору() гарантирует, что мы всегда получим правильный объект строки, независимо от её текущего положения или изменений в табличной части.

Проводим эксперимент: Как это работает на практике

Чтобы лучше понять разницу между идентификатором и индексом, давайте проведем небольшой эксперимент, аналогичный тому, что обсуждался на форуме:

  1. Добавим несколько строк в табличную часть на форме.
  2. Выберем одну из строк и сохраним значение Элементы.Товары.ТекущаяСтрока. Это будет наш уникальный идентификатор.
  3. Удалим несколько других строк из табличной части, или даже ту, которую мы выбрали, а затем добавим новую.
  4. Попытаемся обратиться к табличной части объекта по сохраненному ранее идентификатору как по индексу: Объект.Товары[ТекСтрокаИдентификатор]. Мы увидим ошибку "Индекс находится за границами массива".
  5. Теперь попробуем использовать Объект.Товары.НайтиПоИдентификатору(ТекСтрокаИдентификатор). Если строка с таким идентификатором все еще существует в табличной части объекта, мы получим корректный объект строки. Если строка была удалена, метод вернет Неопределено, но не вызовет ошибку.

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

Обратная операция: Как программно установить текущую строку?

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

Разберем по шагам, как это сделать:

  1. Находим нужный объект строки табличной части в коллекции Объект.Товары, например, по значению какого-либо реквизита.
  2. Вызываем метод ПолучитьИдентификатор() у найденного объекта строки.
  3. Присваиваем полученный идентификатор свойству ТекущаяСтрока нужного табличного поля на форме.

Посмотрим на пример:


// Предположим, у нас есть объект строки табличной части, который мы хотим сделать текущим
// Например, мы нашли его по некому условию
НужнаяСтрокаТЧ = Объект.Товары.Найти(ЗначениеДляПоиска, "ИмяРеквизита");

Если НужнаяСтрокаТЧ <> Неопределено Тогда
    // Получаем идентификатор этой строки
    ИдентификаторДляУстановки = НужнаяСтрокаТЧ.ПолучитьИдентификатор();

    // Устанавливаем текущую строку в табличном поле формы
    Элементы.Товары.ТекущаяСтрока = ИдентификаторДляУстановки;
Иначе
    Сообщить("Строка с заданными параметрами не найдена.");
КонецЕсли;

Важное различие: Табличное поле и Табличная часть объекта

В завершение, давайте еще раз подчеркнем ключевое различие, которое лежит в основе всей этой проблемы:

Метод НайтиПоИдентификатору() позволяет нам эффективно "мостить" эти два мира, безопасно получая доступ к данным объекта, зная только идентификатор строки на форме. Понимание этого фундаментального различия поможет вам избежать многих ошибок при разработке в 1С.

← На главную