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