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