Как программно заполнить список выбора подсистемами и почему выбранное значение может не сохраняться в поле?

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

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача предоставить пользователю возможность выбора определенных объектов метаданных, например, подсистем. Однако начинающие разработчики часто сталкиваются с ситуацией: список успешно заполняется, пользователь выбирает значение, но после выбора поле ввода остается пустым. Разберем детально, как правильно реализовать этот функционал, проанализируем ошибки и рассмотрим наиболее эффективные способы работы со списками выбора на управляемых формах.

Анализ исходной проблемы

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


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

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

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

Причина «пустого поля» после выбора

Выясним причину, по которой поле остается пустым. В 1С управляемые формы работают по строгому принципу соответствия типов. Если реквизит формы имеет тип Строка, то и в СписокВыбора должны попадать значения типа Строка. Основные ошибки здесь обычно две:

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

Оптимальное решение задачи

Посмотрим на более правильный подход, который соответствует стандартам разработки «1С:Совместимо». Вместо того чтобы перебрасывать данные с сервера на клиент и обратно в процедуре ПриОткрытии, лучше выполнить заполнение один раз при создании формы на сервере.

Рассмотрим шаги реализации:

  1. Используем процедуру ПриСозданииНаСервере. Это экономит время, так как форма еще не отображена пользователю, и мы можем напрямую обращаться к свойствам элементов.
  2. Используем метод ЗагрузитьЗначения. Это работает значительно быстрее, чем добавление элементов в цикле.
  3. Удаляем лишние обработчики событий (такие как НачалоВыбора), если нам нужен просто выбор из списка.

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

Работа с иерархией подсистем

Проанализируем важный нюанс: коллекция Метаданные.Подсистемы содержит только подсистемы верхнего уровня (корневые). Если в вашей конфигурации сложная структура, и нужные вам подсистемы вложены друг в друга, вышеуказанный код их «не увидит».

Чтобы собрать абсолютно все подсистемы, разберем пример рекурсивной функции:


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

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Элементы.Подсистема.СписокВыбора.Очистить();
    ЗаполнитьПодсистемыРекурсивно(Метаданные.Подсистемы, Элементы.Подсистема.СписокВыбора);
КонецПроцедуры

Различие между Именем и Синонимом

Для пользователя гораздо удобнее видеть понятное название (Синоним), например, «Продажи и закупки», в то время как программа должна оперировать строгим идентификатором (Имя), например, «ПродажиИЗакупки».

При добавлении элемента в СписокВыбора мы передаем два параметра: Значение и Представление. Выясним, как это работает: Элементы.Подсистема.СписокВыбора.Добавить("ПродажиИЗакупки", "Продажи и закупки"). В этом случае в реквизит запишется краткое имя, а пользователь увидит красивое описание.

Настройка свойств элемента формы в конфигураторе

Чтобы программный код работал корректно, убедимся, что свойства элемента формы (поля ввода) настроены правильно:

Использование события «АвтоПодбор»

Рассмотрим ситуацию, когда подсистем очень много (сотни). Заполнять их все при открытии может быть неэффективно с точки зрения памяти. В таких случаях проанализируем использование события АвтоПодбор. Это позволит формировать список динамически, когда пользователь начинает вводить первые буквы названия подсистемы.


&НаКлиенте
Процедура ПодсистемаАвтоПодбор(Элемент, Текст, ДанныеВыбора, Параметры, СтандартнаяОбработка)
    
    // Если введено меньше 2 символов, не ищем
    Если СтрДлина(Текст) < 2 Тогда
        Возврат;
    КонецЕсли;
    
    СтандартнаяОбработка = Ложь;
    ДанныеВыбора = ПолучитьПодходящиеПодсистемыНаСервере(Текст);
    
КонецПроцедуры

В этом случае серверная функция ПолучитьПодходящиеПодсистемыНаСервере будет фильтровать метаданные по вхождению строки Текст в имя или синоним подсистемы и возвращать готовый СписокЗначений.

Резюме и рекомендации

Подведем итог нашему разбору. Для корректной работы списка выбора в 1С:

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

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

← На главную