К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как получить идентификатор строки дерева значений в 1С

Способы получить идентификатор строки дерева значений в 1С: метод ПолучитьИдентификатор(), поиск по коллекции строк, работа с формой и динамическим списком. Примеры кода и типичные ошибки.

Дерево значений в 1С — иерархическая коллекция, у каждой строки которой есть уникальный внутренний идентификатор. Он нужен, когда дерево выводится в таблицу формы: платформа передаёт в обработчики не саму строку, а её числовой идентификатор, и разработчику требуется выполнить обратное преобразование — либо получить идентификатор по строке, либо найти строку по идентификатору. Без этого невозможно корректно обработать текущую строку, развернуть ветку или программно установить курсор.

Основной инструмент — метод ПолучитьИдентификатор() объекта «СтрокаДереваЗначений». Он возвращает число, уникальное в пределах конкретного дерева, и именно это число используется в свойствах вроде Элементы.Дерево.ТекущаяСтрока и методах формы. Обратная операция выполняется методом НайтиПоИдентификатору(Идентификатор) у дерева значений.

Важно понимать: идентификатор живёт только в рамках текущего экземпляра дерева. После перезагрузки данных, повторного заполнения дерева или выгрузки его в значение и обратной загрузки идентификаторы могут измениться, поэтому хранить их между сеансами работы с данными нельзя.

Что такое идентификатор строки и когда он нужен

Идентификатор строки — целое число, которое платформа присваивает каждой строке дерева значений автоматически при её добавлении. Пользователь не управляет значением идентификатора напрямую: он генерируется системой и гарантированно уникален внутри дерева. На форме элемент «Таблица», связанный с деревом значений, оперирует именно этими числами, а не ссылками на объекты строк.

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

Как получить идентификатор по строке дерева

Если у вас уже есть объект строки — например, найденный поиском или полученный обходом, — вызовите у него метод ПолучитьИдентификатор(). Метод не принимает параметров и возвращает число:

СтрокаДерева = Дерево.Строки.Найти(ИскомоеЗначение, "Номенклатура", Истина);

Если СтрокаДерева <> Неопределено Тогда

ИдСтроки = СтрокаДерева.ПолучитьИдентификатор();

Элементы.Дерево.ТекущаяСтрока = ИдСтроки;

КонецЕсли;

Обратите внимание на третий параметр метода Найти: значение Истина включает поиск по всем уровням иерархии. Если передать Ложь или опустить параметр, поиск выполнится только среди строк верхнего уровня, и нужная вложенная строка не будет найдена — это одна из самых частых причин «неработающего» кода.

После получения идентификатора типичный сценарий — передать его элементу формы. Присвоение Элементы.Дерево.ТекущаяСтрока не только подсвечивает строку, но и автоматически разворачивает родительские ветки до неё, если дерево связано с реквизитом типа «ДеревоЗначений».

1c
СтрокаДерева = Дерево.Строки.Найти(ИскомоеЗначение, "Номенклатура", Истина);
Если СтрокаДерева <> Неопределено Тогда
    Элементы.Дерево.ТекущаяСтрока = СтрокаДерева.ПолучитьИдентификатор();
КонецЕсли;

Как найти строку по идентификатору

Обратная задача встречается чаще: в обработчик события таблицы формы приходит идентификатор, а нужно получить саму строку, чтобы прочитать или изменить её данные. Для этого у дерева значений есть метод НайтиПоИдентификатору(Идентификатор):

&НаКлиенте

Процедура ДеревоПриАктивизацииСтроки(Элемент)

ТекущиеДанные = Элементы.Дерево.ТекущиеДанные;

Если ТекущиеДанные = Неопределено Тогда

Возврат;

КонецЕсли;

// Вариант 1: данные уже доступны через ТекущиеДанные

Наименование = ТекущиеДанные.Наименование;

КонецПроцедуры

На клиенте для чтения данных текущей строки обычно достаточно свойства ТекущиеДанные — оно возвращает объект «ДанныеФормыЭлементДерева» без обращения к серверу. Метод НайтиПоИдентификатору нужен, когда требуется именно объект строки дерева: например, чтобы получить родителя (ПолучитьРодителя()), подчинённые строки или выполнить обход ветки на сервере:

&НаСервере

Функция ПолучитьРодителяСтроки(ИдСтроки)

СтрокаДерева = РеквизитФормыВЗначение("Дерево").НайтиПоИдентификатору(ИдСтроки);

// либо, если работаем с ДанныеФормыДерево напрямую:

СтрокаДерева = Дерево.НайтиПоИдентификатору(ИдСтроки);

Если СтрокаДерева = Неопределено Тогда

Возврат Неопределено;

КонецЕсли;

Возврат СтрокаДерева.ПолучитьРодителя();

КонецФункции

Если идентификатор не найден, метод возвращает Неопределено. Проверка результата обязательна: обращение к свойствам несуществующей строки вызовет ошибку выполнения.

Работа с деревом на форме: реквизит и элемент формы

Когда дерево значений является реквизитом формы, на клиенте и сервере вы работаете с объектом «ДанныеФормыДерево», а не с «ДеревоЗначений» напрямую. У этого объекта также есть методы НайтиПоИдентификатору и у его строк — ПолучитьИдентификатор(), синтаксис полностью совпадает. Преобразование через РеквизитФормыВЗначение требуется только для методов, которых нет у объекта формы, например Скопировать() или Выгрузить().

Типовая последовательность при программном позиционировании на строке после заполнения дерева на сервере выглядит так: заполняете дерево, находите нужную строку, получаете её идентификатор и сохраняете в реквизит формы; на клиенте после обновления присваиваете Элементы.Дерево.ТекущаяСтрока сохранённое значение. Переносить поиск на клиент не стоит — обход большого дерева на клиенте медленнее и в тонком клиенте ограничен.

Порядок действий
  1. 1
    Заполните дерево значений данными на сервере
  2. 2
    Найдите нужную строку методом Найти() с поиском по всем уровням
  3. 3
    Получите идентификатор: СтрокаДерева.ПолучитьИдентификатор()
  4. 4
    Передайте идентификатор элементу формы: Элементы.Дерево.ТекущаяСтрока = Ид
  5. 5
    Проверьте, что строка подсвечена и родительские ветки развернуты

Получение идентификаторов при обходе дерева

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

Процедура ОбойтиДерево(КоллекцияСтрок, СоответствиеИд)

Для Каждого СтрокаДерева Из КоллекцияСтрок Цикл

СоответствиеИд.Вставить(СтрокаДерева.Код, СтрокаДерева.ПолучитьИдентификатор());

ОбойтиДерево(СтрокаДерева.Строки, СоответствиеИд);

КонецЦикла;

КонецПроцедуры

Такое соответствие полезно, если дерево перестраивается редко, а позиционироваться на строках нужно часто: вместо повторного поиска по всем уровням вы получаете идентификатор за одно обращение к соответствию. Помните, что при любом изменении состава строк кэш необходимо пересобирать — иначе в нём останутся идентификаторы уже удалённых строк.

Типичные ошибки и ограничения

Первая распространённая ошибка — попытка использовать идентификатор строки после того, как дерево было очищено и заполнено заново. Старые идентификаторы указывают на несуществующие строки, НайтиПоИдентификатору вернёт Неопределено, а присвоение ТекущаяСтрока несуществующего идентификатора просто снимет выделение. Решение — хранить не идентификатор, а бизнес-ключ строки (код, ссылку) и находить строку заново после каждого перезаполнения.

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

Отдельное ограничение: метод ПолучитьИдентификатор() недоступен для строк, полученных из объекта «ДеревоЗначений», выгруженного вне формы, если затем эти идентификаторы пытаются применить к другому экземпляру дерева. Идентификаторы уникальны только внутри одного экземпляра коллекции.

Типичные ошибки
01
Использование старого идентификатора после перезаполнения дерева — НайтиПоИдентификатору возвращает Неопределено
02
Поиск методом Найти() без третьего параметра Истина — вложенные строки не находятся
03
Обращение к свойствам результата без проверки на Неопределено — ошибка выполнения
04
Хранение идентификаторов между сеансами или передача другому экземпляру дерева — идентификаторы невалидны
Контрольные точки

Как проверить результат

Возврат НайтиПоИдентификатору
Норма

Получен объект строки, доступны её свойства и методы

Тревожный признак

Возвращено Неопределено — идентификатор устарел или дерево перезаполнено

Позиционирование на форме
Норма

Строка подсвечена, родительские ветки развернуты

Тревожный признак

Выделение снято или курсор остался на прежней строке

Обход дерева
Норма

Каждая строка возвращает уникальное число

Тревожный признак

Дубли идентификаторов — вероятно, смешаны строки разных экземпляров дерева

Частые вопросы

Чем идентификатор строки отличается от номера строки?

Номер строки — порядковый индекс в коллекции родителя, он меняется при сортировке и удалении соседних строк. Идентификатор — уникальное число, присвоенное платформой, не зависящее от позиции строки в иерархии. Для адресации строк на форме используется только идентификатор.

Можно ли задать идентификатор строки вручную?

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

Как получить идентификатор текущей строки дерева на клиенте?

Прочитайте свойство Элементы.Дерево.ТекущаяСтрока — оно содержит идентификатор активной строки. Данные самой строки доступны через Элементы.Дерево.ТекущиеДанные без дополнительных вызовов.

Что вернёт НайтиПоИдентификатору, если строка удалена?

Метод вернёт Неопределено. Поэтому перед использованием результата всегда выполняйте проверку: Если СтрокаДерева = Неопределено Тогда Возврат; КонецЕсли.

Сохраняются ли идентификаторы после ЗначениеВРеквизитФормы?

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

Как развернуть всё дерево программно?

Обойдите строки верхнего уровня и для каждой вызовите Элементы.Дерево.Развернуть(Строка.ПолучитьИдентификатор(), Истина) — второй параметр включает разворачивание всех подчинённых уровней. Для сворачивания используется метод Свернуть() с тем же идентификатором.

Итог

Что важно запомнить

Идентификатор строки дерева получают методом СтрокаДерева.ПолучитьИдентификатор(), обратный поиск — Дерево.НайтиПоИдентификатору(Ид). Идентификаторы действительны только внутри текущего экземпляра дерева и теряют силу после его перезаполнения, поэтому для восстановления позиции храните бизнес-ключ строки, а не сам идентификатор.