Как задать тип элементов списка значений для составного реквизита в управляемых формах 1С?

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

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

Почему платформа требует выбирать тип для каждого элемента

Проанализируем механику работы платформы с составными типами. Если реквизит имеет строго один тип — СписокЗначений, конфигуратор позволяет декларативно настроить свойство Тип значения, указав допустимый тип элементов (например, ссылку на справочник). В этом случае встроенный редактор сразу открывает форму выбора нужного справочника без промежуточных окон.

Однако если реквизит является составным (включает и ссылку на справочник, и список значений), поле настройки типа элементов списка в конфигураторе становится недоступным. При интерактивной смене типа в интерфейсе платформа создает новый пустой объект СписокЗначений, у которого свойство ТипЗначения содержит пустое ОписаниеТипов. В результате список готов принять абсолютно любые данные, и платформа вынуждена каждый раз спрашивать пользователя, какой именно тип он собирается ввести.

Способ 1. Программная типизация списка при открытии или чтении формы

Разберем базовое решение, предложенное в обсуждении. Для того чтобы список знал, какие типы данных в нем допустимы, необходимо программно задать его свойство ТипЗначения с помощью объекта ОписаниеТипов.

Если реквизит уже содержит СписокЗначений при загрузке формы (или создается по умолчанию), инициализируем его в серверном обработчике формы. Посмотрим на пример кода:


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

Обратите внимание: если данные реквизита хранятся в базе данных через сериализацию (например, в реквизите типа ХранилищеЗначения), после считывания свойство ТипЗначения может не восстановиться автоматически. В таком случае аналогичную процедуру типизации обязательно выполняем в обработчике ПриЧтенииНаСервере.

Способ 2. Обработка интерактивной смены типа и вызова диалога

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

Настроим логику по шагам:

  1. В событии ПриИзменении поля ввода проверяем, какой тип выбрал пользователь. Если выбран СписокЗначений, немедленно ограничиваем его тип.
  2. В событии НачалоВыбора перед открытием диалога редактирования списка дополнительно проверяем и при необходимости устанавливаем тип элементов.

Посмотрим на пример реализации клиентских обработчиков формы:


&НаКлиенте
Процедура СоставнойРеквизитПриИзменении(Элемент)
    
    Если ТипЗнч(Объект.СоставнойРеквизит) = Тип("СписокЗначений") Тогда
        УстановитьТипЭлементовСписка(Объект.СоставнойРеквизит);
    КонецЕсли;
    
КонецПроцедуры

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

&НаКлиенте
Процедура УстановитьТипЭлементовСписка(Список)
    
    ТипСтр = "СправочникСсылка.Номенклатура";
    Список.ТипЗначения = Новый ОписаниеТипов(ТипСтр);
    
КонецПроцедуры

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

Способ 3. Переопределение выбора через множественный подбор

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

Для этого в событии НачалоВыбора отключаем стандартную обработку и открываем форму выбора нужного справочника:


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

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

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

Альтернативные архитектурные решения

В реальной практике хранение списков значений внутри составного реквизита объекта часто приводит к сложностям при построении отчетов и запросов. Рассмотрим рекомендации опытных разработчиков по оптимизации архитектуры:

  1. Использование табличной части. Если для объекта предполагается хранение множества значений, надежнее вынести эти данные в отдельную табличную часть. Это упрощает контроль типов, контроль ссылочной целостности и написание запросов.
  2. Разделение элементов на форме через переключатель. Вместо одного поля составного типа можно создать на форме два отдельных поля: одно для одиночной ссылки, второе — для списка (или таблицы). С помощью переключателя («Одиночный выбор» / «Список») разработчик управляет видимостью нужного поля. При таком подходе реквизит списка имеет строго определенный тип, заданный в конфигураторе, что исключает любые сбои типизации.
← На главную