Как правильно изменить значения в выделенных строках таблицы управляемой формы 1С

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

При разработке интерфейсов на управляемых формах 1С:Предприятие 8 часто возникает задача массовой обработки строк, которые пользователь выделил в таблице (элемент формы типа Таблица). Одной из наиболее распространенных ошибок является попытка обращения к строкам по их порядковому номеру (индексу) внутри цикла. В данной статье мы подробно разберем, почему возникает ошибка "Индекс находится за границами массива", и как правильно модифицировать данные, используя уникальные идентификаторы.

Анализируем причину возникновения ошибки

Рассмотрим стандартную ситуацию. У нас есть документ, в табличной части которого пользователь выбирает несколько строк. Мы открываем вспомогательную форму, получаем оттуда новые значения (например, время начала и окончания работ) и пытаемся применить их к выделенным строкам. Типичный, но ошибочный код выглядит так:


Для Каждого Индекс Из Элементы.ДанныеОВремени.ВыделенныеСтроки Цикл
    Объект.ДанныеОВремени[Индекс].ВремяС = ВыбранноеЗначение.ВремяС;
    Объект.ДанныеОВремени[Индекс].ВремяПо = ВыбранноеЗначение.ВремяПо;
КонецЦикла;

Проблема заключается в фундаментальном различии между Индексом и Идентификатором строки в управляемых формах. Давайте разберем по шагам, что происходит в системе:

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

Правильное решение через поиск по идентификатору

Чтобы избежать ошибок, связанных с изменением состава строк или их сортировкой, мы должны использовать метод НайтиПоИдентификатору(). Этот метод позволяет получить объект строки непосредственно по тому значению, которое хранится в массиве выделенных строк.

Рассмотрим исправленный алгоритм работы в обработчике оповещения или выбора:


// Проверяем имя формы, из которой вернулись данные
ИначеЕсли ИсточникВыбора.ИмяФормы = "Документ.УчетРабочегоВремени.Форма.ФормаИзмененияВремени" Тогда
    
    // Получаем массив уникальных идентификаторов выделенных строк
    МассивИдентификаторов = Элементы.ДанныеОВремени.ВыделенныеСтроки;
    
    Для Каждого Идентификатор Из МассивИдентификаторов Цикл
        
        // Находим строку в данных объекта по её ID
        СтрокаДляОбработки = Объект.ДанныеОВремени.НайтиПоИдентификатору(Идентификатор);
        
        // Обязательно проверяем, не удалена ли строка к этому моменту
        Если СтрокаДляОбработки <> Неопределено Тогда
            СтрокаДляОбработки.ВремяС = ВыбранноеЗначение.ВремяС;
            СтрокаДляОбработки.ВремяПо = ВыбранноеЗначение.ВремяПо;
        КонецЕсли;
        
    КонецЦикла;

КонецЕсли;

В данном примере Объект.ДанныеОВремени — это коллекция типа ДанныеФормыКоллекция, которая поддерживает метод поиска по ID. Это гарантирует, что мы обратимся именно к той строке, которую видел и выбирал пользователь, даже если в процессе обработки порядок строк изменился.

Оптимизация работы и серверный контекст

Разберем ситуацию, когда строк в таблице очень много (несколько тысяч), и нам нужно выполнить сложную обработку на сервере. Важно помнить, что объект Элементы доступен только на клиенте. Поэтому, если мы хотим передать выделенные строки на сервер, нам нужно сначала собрать их идентификаторы в массив.

Проанализируем пример эффективного перехода с клиента на сервер:


&НаКлиенте
Процедура ОбработатьВыделенные(Команда)
    МассивID = Элементы.СписокНоменклатуры.ВыделенныеСтроки;
    ОбработатьНаСервере(МассивID);
КонецПроцедуры

&НаСервере
Процедура ОбработатьНаСервере(МассивID)
    Для Каждого ID Из МассивID Цикл
        СтрокаДанных = Объект.Товары.НайтиПоИдентификатору(ID);
        Если СтрокаДанных <> Неопределено Тогда
            // Выполняем сложные расчеты
            СтрокаДанных.Цена = ПолучитьЦенуНаСервере(СтрокаДанных.Номенклатура);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

Почему использование "Попытка...Исключение" — это плохая практика?

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

Подведем итоги

Для надежной работы с выделенными строками в 1С всегда следуйте трем правилам:

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

Использование правильных методов работы с коллекциями не только избавляет от досадных ошибок "out of bounds", но и делает ваш код более читаемым и профессиональным. Помните, что понимание жизненного цикла идентификаторов в управляемом приложении — это ключ к созданию стабильных и отзывчивых интерфейсов.

← На главную