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