Как правильно работать с выделенными строками в таблице после её очистки и повторного заполнения

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

В практике разработки на платформе 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. Сортировка: Если пользователь нажал на заголовок колонки и отсортировал таблицу, визуальный порядок строк изменится. Строка, которая была первой (индекс 0), может стать последней. Но её идентификатор (ID) останется прежним, и НайтиПоИдентификатору вернет именно те данные, на которые кликнул пользователь.
  2. Фильтрация: При использовании поиска или отборов часть строк скрывается. Индексация в коллекции объекта при этом не меняется, что может привести к путанице при попытке сопоставить «номер в списке на экране» с «номером в массиве».
  3. Динамические списки: Если вы работаете не с табличной частью, а с динамическим списком (например, список документов), то в ВыделенныеСтроки вообще будут лежать ссылки на объекты базы данных (ДокументСсылка, СправочникСсылка), а не числа.

Дополнительный способ: метод ДанныеСтроки()

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

Рассмотрим пример его использования:


&НаКлиенте
Процедура ПримерИспользованияДанныеСтроки()
    
    Для Каждого ИдСтроки Из Элементы.ТЧСписок.ВыделенныеСтроки Цикл
        
        // Получаем данные конкретной строки через элемент управления
        ДанныеВыделеннойСтроки = Элементы.ТЧСписок.ДанныеСтроки(ИдСтроки);
        
        Если ДанныеВыделеннойСтроки <> Неопределено Тогда
            // Мы получили доступ к колонкам строки таблицы формы
            НужноеЗначение = ДанныеВыделеннойСтроки.Количество;
            Сообщить("Значение в колонке: " + НужноеЗначение);
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

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

Резюме для разработчика

Проанализировав проблему, мы можем сформулировать золотое правило работы с таблицами в 1С:

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

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

← На главную