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