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