В процессе разработки на платформе 1С:Предприятие 8.3 многие программисты, особенно переходящие с обычных форм на управляемые, сталкиваются с ситуацией, которую ошибочно принимают за критический баг платформы. Суть проблемы заключается в "странном" поведении индексов табличной части: после удаления строк или очистки таблицы новые строки получают значения, которые постоянно растут и не соответствуют порядковому номеру строки. Рассмотрим, почему это происходит, разберем внутреннюю логику работы управляемого интерфейса и научимся правильно манипулировать данными в коллекциях формы.
Проанализируем типичный сценарий. Разработчик создает обработку, добавляет в неё табличную часть и выводит её на форму. При попытке программно получить данные текущей строки через Элементы.ТабличнаяЧасть.ТекущаяСтрока, он ожидает получить число 0 для первой строки, 1 для второй и так далее. Однако, если таблицу очистить и добавить строку заново, это свойство вернет значение, значительно превышающее ноль.
Важно понимать: в управляемых формах свойство ТекущаяСтрока элемента формы "Таблица" возвращает не индекс (порядковый номер), а внутренний уникальный идентификатор строки. Этот идентификатор генерируется платформой автоматически и гарантирует уникальность строки в рамках текущего времени жизни формы. Рассмотрим основные различия:
Выясним причину такого поведения. Это необходимо для корректной работы клиент-серверной архитектуры. Когда вы работаете в тонком клиенте, данные таблицы не передаются целиком при каждом действии. Использование неизменных идентификаторов позволяет системе точно знать, какую именно строку пользователь редактирует в данный момент, даже если на сервере в этот момент коллекция была пересортирована другим фоновым процессом.
Посмотрим на пример кода, который часто приводит к ошибке "Индекс находится за границами коллекции". Проблема возникает, когда идентификатор (например, 10) подставляется в метод Получить(), который ожидает индекс (от 0 до количества строк минус 1).
Разберем, как правильно получить объект строки, зная её идентификатор. Для этого в коллекциях ДанныеФормыКоллекция (которыми являются табличные части на форме) существует специальный метод НайтиПоИдентификатору().
&НаКлиенте
Процедура КомандаИндекс(Команда)
// Получаем идентификатор (это НЕ индекс!)
ИдентификаторТекущейСтроки = ЭтаФорма.Элементы.ТабличнаяЧасть1.ТекущаяСтрока;
Если ИдентификаторТекущейСтроки = Неопределено Тогда
Возврат;
КонецЕсли;
// ПРАВИЛЬНЫЙ ПУТЬ: получение элемента коллекции по идентификатору
ТекСтрокаДанных = ЭтаФорма.Объект.ТабличнаяЧасть1.НайтиПоИдентификатору(ИдентификаторТекущейСтроки);
Если ТекСтрокаДанных <> Неопределено Тогда
Сообщить("Значение текущей строки: " + ТекСтрокаДанных.ЗначСтрока);
// Если нам все же нужен индекс (порядковый номер)
ПорядковыйИндекс = ЭтаФорма.Объект.ТабличнаяЧасть1.Индекс(ТекСтрокаДанных);
Сообщить("Порядковый номер в таблице (с нуля): " + Строка(ПорядковыйИндекс));
КонецЕсли;
КонецПроцедуры
Проанализируем еще одну ошибку, связанную с неправильным расчетом индексов при удалении. Автор темы в Сообщении 0 предлагал удалять все строки через Удалить(0) в цикле по количеству строк. Это классический способ, но в управляемом приложении при работе с объектом ДанныеФормыКоллекция на клиенте лучше придерживаться следующих правил.
Если вам нужно полностью очистить таблицу, всегда используйте метод Очистить(). Это работает быстрее и корректнее с точки зрения уведомления интерфейса об изменениях.
&НаКлиенте
Процедура ОчиститьТаблицу()
// Это обнулит строки, но внутренний счетчик идентификаторов платформы продолжит расти
ЭтаФорма.Объект.ТабличнаяЧасть1.Очистить();
КонецПроцедуры
Если же необходимо удалить конкретные строки по условию, то использование индексов в прямом цикле (от 0 до N) приведет к ошибке, так как после удаления первой строки вторая "прыгнет" на её место, и ваш счетчик i пропустит её. В таких случаях мы рекомендуем использовать обратный цикл или коллекцию для удаления.
&НаКлиенте
Процедура УдалитьВыбранныеСтроки()
Таблица = ЭтаФорма.Объект.ТабличнаяЧасть1;
Колво = Таблица.Количество();
// Обходим таблицу с конца к началу
Для i = 1 По Колво Цикл
ИндексСтроки = Колво - i;
ТекСтрока = Таблица.Получить(ИндексСтроки);
Если ТекСтрока.НужноУдалить Тогда
Таблица.Удалить(ИндексСтроки);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Интересное наблюдение было сделано в обсуждении: использование метода Загрузить(ТаблицаЗначений) часто приводит к тому, что идентификаторы строк снова начинаются с малых значений. Рассмотрим причину: метод Загрузить() не просто добавляет строки, он полностью пересоздает структуру данных коллекции в памяти формы. Поскольку старые связи разрываются, платформа инициализирует коллекцию заново, что может привести к обнулению счетчика идентификаторов (auto-increment).
Однако полагаться на это поведение в логике программы нельзя. Программный код должен быть универсальным и всегда рассчитывать на то, что ТекущаяСтрока — это произвольное уникальное число.
Важно помнить, что поведение свойства ТекущаяСтрока зависит от типа данных, отображаемых в таблице:
ДанныеФормыКоллекция), то возвращается Число (Идентификатор).СправочникСсылка или ДокументСсылка), либо значение ключа записи (для регистров).Проанализируем пример из Сообщения 22, где разработчик пытается найти строку по идентификатору, перебирая числа в цикле. Это крайне неэффективный подход. Если вам нужно найти строку по какому-то признаку, используйте метод НайтиСтроки(), который возвращает массив элементов коллекции, удовлетворяющих условию поиска. Это избавит вас от необходимости знать идентификаторы или индексы.
Подведем итоги нашего разбора. То, что автор темы принял за ошибку 1С 8.3.14.1630, на самом деле является фундаментальным принципом работы управляемых форм. Индексы нужны для доступа к элементам в упорядоченном массиве, а идентификаторы — для однозначного определения строки в интерактивном интерфейсе.
Для стабильной работы кода придерживайтесь следующих правил:
Элементы.ВашаТаблица.ТекущаяСтрока в методе Объект.ВашаТаблица.Получить().Элементы.Таблица.ТекущаяСтрока -> Объект.Таблица.НайтиПоИдентификатору().Элементы.Таблица.ТекущаяСтрока = Объект.Таблица[НужныйИндекс].ПолучитьИдентификатор().Понимание этой разницы между данными (Объект) и их визуальным представлением (Элементы) — первый шаг к написанию качественного кода на платформе 1С:Предприятие 8.3. Для практического освоения динамической работы с коллекциями формы пригодится пример программного вывода произвольной таблицы значений на управляемую форму.