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