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