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