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