Как правильно работать со списком выбора в управляемых формах 1С 8.3 и избежать типичных ошибок с привязкой данных

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

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

Ошибка 1. Инициализация списка в событии ПриОткрытии на клиенте

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


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

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

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

Перенесем инициализацию на сервер:


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

Ошибка 2. Конфликт типов данных (Несоответствие значения и реквизита)

Это одна из самых коварных ошибок, из-за которой элементы списка отображаются на экране, но при попытке выбрать любой из них значение в поле ввода просто исчезает или сбрасывается. Проанализируем пример кода, с которым столкнулся автор темы:


// ВключатьНДС — реквизит формы с типом "Строка"
Элементы.ВключатьНДС.СписокВыбора.Очистить();                             
Элементы.ВключатьНДС.СписокВыбора.Добавить(1, "без учета НДС"); // Здесь передается Число
Элементы.ВключатьНДС.СписокВыбора.Добавить(2, "с учетом НДС");  // И здесь Число

Давайте выясним причину такого поведения платформы. Метод Добавить() для списка значений принимает несколько параметров: СписокВыбора.Добавить(Значение, Представление).

  1. Значение (первый параметр) — это то, что физически записывается в реквизит формы при выборе пункта пользователем. В примере выше это числа 1 и 2.
  2. Представление (второй параметр) — это просто текстовая строка, которую видит пользователь на экране (например, "без учета НДС").

Если связанный реквизит формы (заданный в свойстве ПутьКДанным элемента управления) имеет тип Строка, а вы пытаетесь записать туда числовое значение 1 или 2 из списка выбора, происходит неявный конфликт типов. Платформа 1С обнаруживает строгое несовпадение типов данных между выбранным значением списка (Число) и реквизитом формы (Строка) и мгновенно сбрасывает выбор в значение по умолчанию (пустую строку).

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

Вариант А. Сохраняем тип реквизита "Строка". В этом случае числа-идентификаторы в методе Добавить() также должны передаваться как строки (в кавычках):


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Элементы.ВключатьНДС.СписокВыбора.Очистить();                            
    Элементы.ВключатьНДС.СписокВыбора.Добавить("1", "без учета НДС"); // Передаем строку "1"
    Элементы.ВключатьНДС.СписокВыбора.Добавить("2", "с учетом НДС");  // Передаем строку "2"
КонецПроцедуры

Вариант Б. Меняем тип реквизита формы на "Число". Если в коде обработок и запросов вам удобнее оперировать числами (например, для условий Если Сортировка = 1 Тогда), измените тип реквизита формы на Число в редакторе формы. Тогда исходный программный код заработает корректно:


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

Ошибка 3. Путаница между Элементами и Реквизитами в управляемых формах

Переходя со старой парадигмы программирования 1С (обычные формы), разработчики по привычке пытаются обращаться к значениям полей формы через коллекцию элементов управления, совершая грубейшую ошибку:


// Внимание: ТАК ДЕЛАТЬ НЕЛЬЗЯ!
Если Элементы.Сортировка = 1 Тогда 
    // ...
КонецЕсли;

Давайте разберем, почему этот код вызовет критическую ошибку выполнения. В управляемом приложении строго разделены Данные (Реквизиты) и Интерфейс (Элементы).

Правильное обращение к данным: Для чтения или записи значений реквизитов формы в модуле управляемой формы обращайтесь к ним напрямую по имени (в контексте формы они доступны как локальные переменные модуля):


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

Разбор лучших практик проектирования списков выбора

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

Альтернатива 1. Использование типа Булево для бинарных переключателей

Если ваш список выбора содержит ровно два противоположных значения (например, "без учета НДС" и "с учетом НДС"), то использование строкового реквизита избыточно. Гораздо правильнее настроить реквизит с типом Булево.

Выполним настройку по шагам:

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

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Элементы.УчитыватьНДС.СписокВыбора.Очистить();
    Элементы.УчитыватьНДС.СписокВыбора.Добавить(Ложь, "без учета НДС");
    Элементы.УчитыватьНДС.СписокВыбора.Добавить(Истина, "с учетом НДС");
КонецПроцедуры

Теперь ваш код в модуле формы или при формировании отчетов избавится от ненадежных строковых проверок и станет максимально простым и лаконичным:


Если УчитыватьНДС Тогда
    // Код расчета с НДС
Иначе
    // Код расчета без НДС
КонецЕсли;

Альтернатива 2. Использование системных Перечислений

Для более сложных списков выбора (например, вариантов сортировки отчета: по периодам, по покупателям, по номенклатуре) идеальным решением является создание объекта метаданных Перечисление в конфигураторе.

Давайте проанализируем преимущества этого подхода:

Пример безопасного использования значений перечисления в условиях:


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

Используя эти простые правила разделения контекстов, типизации данных и современные стандарты разработки 1С, вы сможете проектировать стабильные, быстрые и удобные интерфейсы для любых бизнес-решений.

← На главную