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