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