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