Почему свойство ТекущаяСтрока в таблице управляемой формы 1С ведет себя странно и как правильно получить данные строки?

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

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

Разбираем причину проблемы: Идентификатор против Индекса

Давайте проанализируем ситуацию, описанную в теме. Разработчик использует свойство Элементы.ИмяТаблицы.ТекущаяСтрока и пытается на его основе обращаться к коллекции данных как к массиву по индексу. В этом кроется главная архитектурная ошибка. ТекущаяСтрока — это не индекс строки в коллекции данных, а ее внутренний уникальный идентификатор.

Рассмотрим разницу подробнее:

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

Именно поэтому, когда автор темы удалял строки и добавлял новые, ТекущаяСтрока возвращала значение "2" при фактическом наличии всего одной строки в таблице. Попытка обратиться к Коллекция[2] приводила к аварийному завершению работы кода.

Решение №1: Использование свойства ТекущиеДанные (для клиента)

Самый простой и правильный способ получить доступ к данным строки на стороне клиента — это использование свойства ТекущиеДанные элемента формы "Таблица". Это свойство сразу возвращает объект типа ДанныеФормыСтруктура, который содержит все колонки текущей строки.

Рассмотрим пример кода, который позволяет добавить данные во вложенную таблицу, основываясь на текущем выборе пользователя:


// Пример правильного получения текущих данных на клиенте
Процедура ДобавитьКонтрагентовВГруппу(Команда)
    
    ТекущиеДанные = Элементы.ГруппаПолучатели.ТекущиеДанные;
    
    // Проверяем, выбрана ли строка вообще
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Обращаемся напрямую к вложенной коллекции (например, к списку получателей)
    ТекущиеПолучатели = ТекущиеДанные.Получатели;
    
    // Теперь мы можем работать с коллекцией строк без поиска по индексам
    Для каждого Эл Из МассивВыбранныхАдресов Цикл
        НоваяСтрока = ТекущиеПолучатели.Добавить();
        НоваяСтрока.Представление = Эл.Представление;
        НоваяСтрока.Email = Эл.Адрес;
    КонецЦикла;
    
КонецПроцедуры

Этот подход избавляет нас от необходимости знать индекс строки или ее идентификатор. Мы работаем непосредственно с объектом данных, на который указывает курсор пользователя.

Решение №2: Метод НайтиПоИдентификатору (для сервера)

Иногда логика требует передачи управления на сервер. Однако объект Элементы (содержащий ТекущиеДанные) на сервере недоступен. В этом случае мы должны использовать связку идентификатора и метода поиска в коллекции Объект.

Разберем этот алгоритм по шагам:

  1. На клиенте получаем идентификатор строки через ТекущаяСтрока.
  2. Передаем этот идентификатор в серверную процедуру.
  3. На сервере находим нужную строку в данных формы.

Пример реализации:


&НаКлиенте
Процедура ОбработатьСтрокуНаСервере()
    
    // 1. Получаем идентификатор (это число или ссылка для дин.списка)
    ИдСтроки = Элементы.ГруппаПолучатели.ТекущаяСтрока;
    
    Если ИдСтроки = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ВыполнитьДействиеНаСервере(ИдСтроки);
    
КонецПроцедуры

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

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

Важные нюансы при работе с таблицами

Проанализируем дополнительные технические моменты, которые помогут избежать ошибок в будущем:

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

2. Динамические списки. Если ваша таблица отображает данные ДинамическогоСписка (например, список справочника "Контрагенты"), то свойство ТекущаяСтрока будет возвращать не число-идентификатор, а Ссылку на объект БД. В этом случае поиск строки на сервере вообще не требуется — вы просто работаете со ссылкой напрямую.

3. Свойство "Использовать всегда". Рассмотрим ситуацию: вы пытаетесь получить значение колонки через ТекущиеДанные, но эта колонка не выведена на экран (скрыта программно или пользователем). Система может вернуть пустые данные или Неопределено. Чтобы данные скрытых колонок были доступны в коде, найдите реквизит в дереве данных формы и установите для него флаг Использовать всегда.

Почему использование своего GUID — это "костыль"?

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

Однако, создание собственного идентификатора может быть оправдано только в одном случае: если вы полностью очищаете таблицу методом Загрузить(). При полной перезагрузке коллекции старые системные идентификаторы аннулируются, и только ваш собственный ID позволит восстановить фокус на нужной записи.

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

Для эффективной работы с таблицами на управляемых формах запомните следующие правила:

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

Следуя этим рекомендациям, вы сделаете свой код надежным, производительным и устойчивым к действиям пользователя по сортировке и фильтрации списков.

← На главную