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