Как программно установить тип значения поля дерева значений в зависимости от уровня строки

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с управляемыми формами 1С часто возникает задача сделать интерфейс максимально удобным и интуитивно понятным. Одной из таких задач является динамическое изменение типа данных в одной и той же колонке дерева значений. Например, когда на верхнем уровне (узел дерева) мы хотим выбирать сотрудника, а на подчиненном уровне — конкретный критерий его оценки. Рассмотрим подробно, как это реализовать правильно, избегая лишних диалоговых окон выбора типа.

Разбор проблемы и типичные ошибки

Проанализируем ситуацию: у нас есть дерево значений с колонкой СотрудникКритерий. Данная колонка имеет составной тип, включающий СправочникСсылка.Сотрудники и СправочникСсылка.КритерииОценки. По умолчанию 1С при попытке выбора в такой колонке сначала предложит пользователю выбрать сам тип данных (Сотрудник или Критерий), и только потом откроет нужный справочник. Это создает лишние клики и замедляет работу.

Попытки использовать свойство ДоступныеТипы или устанавливать тип в событии ПередНачаломДобавления часто не приносят результата, так как это свойство больше предназначено для описания метаданных, а не для оперативного управления поведением элемента управления в конкретной строке. Выясним, как управлять процессом выбора программно.

Решение через событие НачалоВыбора

Наиболее эффективным способом управления типами в строках дерева значений является использование события НачалоВыбора для конкретного элемента формы (поля ввода). Разберем по шагам, как настроить это событие.

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


&НаКлиенте
Процедура ДеревоКритериевСотрудникКритерийНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    // Получаем текущие данные строки
    ТекущаяСтрока = Элементы.ДеревоКритериев.ТекущиеДанные;
    
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;

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

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

В этом коде мы используем свойство ОграничениеТипа. Оно позволяет сузить составной тип реквизита до одного конкретного типа в контексте текущего действия. Установка свойства ВыборТипа = Ложь заставляет систему пропустить шаг с вопросом "Тип значения" и сразу открыть форму выбора справочника.

Подготовка данных: Составной тип реквизита

Проанализируем важный нюанс: чтобы вышеуказанный код работал, сам реквизит дерева значений (колонка СотрудникКритерий) обязательно должен иметь составной тип в метаданных формы. Если вы укажете там только ЛюбаяСсылка, система может вести себя нестабильно. Рекомендуется четко перечислить в типе реквизита те справочники, которые будут участвовать в выборе.

Алгоритм настройки реквизита:

  1. Откройте редактор формы.
  2. Перейдите на закладку "Реквизиты".
  3. Найдите ваше дерево значений и нужную колонку.
  4. В свойстве "Тип" нажмите кнопку выбора и отметьте галочками нужные справочники.
  5. В свойствах элемента формы (поля ввода) убедитесь, что снята галочка "Выбирать тип", если вы планируете полностью контролировать процесс программно.

Использование события ПриАктивизацииСтроки

Иногда требуется, чтобы кнопка выбора в поле ввода меняла свой вид (или само поле очищалось при несовпадении типов) еще до того, как пользователь нажмет на нее. В этом случае полезно дублировать логику ограничения типов в событии ПриАктивизацииСтроки. Рассмотрим, как это выглядит:


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

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

Особенности работы с методом ПолучитьРодителя()

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

Однако, если ваше дерево имеет более сложную структуру (например, 3 и более уровней), лучше использовать проверку на наличие конкретных данных в служебных колонках. Например, можно добавить в дерево скрытую колонку ЭтоСотрудник (тип Булево), которая заполняется при формировании дерева на сервере. Это сделает код на клиенте более простым и надежным:


Если ТекущиеДанные.ЭтоСотрудник Тогда
    Элемент.ОграничениеТипа = Новый ОписаниеТипов("СправочникСсылка.Сотрудники");
Иначе
    Элемент.ОграничениеТипа = Новый ОписаниеТипов("СправочникСсылка.КритерииОценки");
КонецЕсли;

Резюме для реализации

Подведем итоги. Для реализации динамической смены типа в дереве значений необходимо:

  1. Установить составной тип для реквизита колонки в дереве значений.
  2. Использовать свойство ОграничениеТипа элемента формы вместо ДоступныеТипы.
  3. Всегда устанавливать ВыборТипа = Ложь, чтобы подавить стандартное окно выбора типа 1С.
  4. Проверять уровень строки через ПолучитьРодителя() или через вспомогательную колонку.

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

← На главную