Как программно заполнить реквизит составного типа на управляемой форме 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Работа с составными типами данных в 1С:Предприятие 8.3 на управляемых формах часто преподносит сюрпризы начинающим разработчикам. Типичная ситуация: в коде значение реквизиту присвоено, отладчик подтверждает наличие данных, но на самой форме поле остается пустым или отображает старое значение. Особенно остро эта проблема проявляется, когда у элемента управления включен режим выбора из списка или заданы жесткие ограничения типов. В рамках данной статьи мы разберем, почему возникает этот эффект «пустого поля» и как правильно реализовать программное заполнение таких реквизитов.

Почему значение в реквизите есть, а на форме его нет?

Для начала проанализируем механику работы управляемой формы. Когда мы пишем Объект.Источник = НужнаяСсылка, мы изменяем данные в реквизите формы (в данных объекта). Однако элемент управления (поле ввода), который отображает этот реквизит, имеет свои собственные настройки. Если тип данных реквизита составной (например, СправочникСсылка.Подразделения и Строка), платформа должна понимать, какой именно тип сейчас активен и как его визуализировать.

Существует несколько основных причин, по которым визуальное обновление не происходит:

  1. Режим выбора из списка (ChoiceModeFromList): Если у элемента формы установлено это свойство, поле ввода будет отображать только те значения, которые содержатся в коллекции СписокВыбора. Если вы программно записали в реквизит ссылку на подразделение, которой нет в списке выбора, платформа просто «не знает», как ее показать в этом режиме, и оставляет поле пустым.
  2. Ограничение типа (TypeRestriction): Если на элементе формы программно или в свойствах установлено ограничение типа (например, только Строка), а вы пытаетесь записать туда СправочникСсылка, возникнет конфликт отображения.
  3. Несоответствие типов: При программном заполнении составного реквизита важно не просто присвоить ссылку, но и убедиться, что тип значения в реквизите соответствует ожидаемому типу в элементе формы.

Решение 1: Программная установка типа и значения

Рассмотрим самый прямой способ решения проблемы, который обсуждался в сообщениях темы. Чтобы значение отобразилось, нам нужно явно указать элементу формы, какой тип данных мы сейчас используем, и присвоить само значение.

Предположим, у нас есть процедура, срабатывающая при изменении какого-то флага на форме. Нам нужно установить в реквизит Источник конкретное подразделение, полученное с сервера. Проанализируем правильный алгоритм действий:


&НаКлиенте
Процедура УстановитьПодразделениеПриИзменении(Элемент)
    
    Если Объект.НужныйФлаг Тогда
        // 1. Устанавливаем ограничение типа для элемента формы
        НовоеОграничение = Новый ОписаниеТипов("СправочникСсылка.Подразделения");
        Элементы.Источник.ОграничениеТипа = НовоеОграничение;
        
        // 2. Получаем ссылку на подразделение с сервера
        СсылкаПодразделение = ПолучитьПодразделениеНаСервере();
        
        // 3. Присваиваем значение реквизиту объекта
        Объект.Источник = СсылкаПодразделение;
        
        // 4. Если используется СписокВыбора, нужно добавить значение туда
        Если Элементы.Источник.РежимВыбораИзСписка Тогда
             Если Элементы.Источник.СписокВыбора.НайтиПоЗначению(СсылкаПодразделение) = Неопределено Тогда
                 Элементы.Источник.СписокВыбора.Добавить(СсылкаПодразделение);
             КонецЕсли;
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьПодразделениеНаСервере()
    // Замените на вашу логику поиска
    Возврат Справочники.Подразделения.НайтиПоКоду("000000001");
КонецФункции

Важный момент: использование НаСервереБезКонтекста предпочтительнее для простых функций получения данных, так как это ускоряет работу формы, не передавая весь контекст объекта на сервер и обратно.

Решение 2: Использование событий НачалоВыбора и ОбработкаВыбора

Если логика требует, чтобы пользователь сначала выбирал категорию (например, "Подразделение" или "Клиент"), а затем уже само значение, лучше всего использовать стандартные события элемента управления. Это позволит избежать «хаков» со списками выбора и сделает поведение формы предсказуемым.

Разберем, как это реализовать через перехват выбора:


&НаКлиенте
Процедура ИсточникНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    // Отменяем стандартное окно выбора типа
    СтандартнаяОбработка = Ложь;
    
    // Формируем свой список категорий
    СписокКатегорий = Новый СписокЗначений;
    СписокКатегорий.Добавить("Клиент", "Выбрать клиента");
    СписокКатегорий.Добавить("Подразделение", "Выбрать подразделение");
    
    // Показываем список пользователю
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораКатегории", ЭтаФорма);
    СписокКатегорий.ПоказатьВыборИзСписка(ОписаниеОповещения);
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораКатегории(ВыбранныйЭлемент, Параметры) Экспорт
    Если ВыбранныйЭлемент = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    Если ВыбранныйЭлемент.Значение = "Подразделение" Тогда
        // Открываем форму выбора справочника
        ПараметрыВыбора = Новый Структура("ЗакрыватьПриВыборе", Истина);
        ОписаниеЗавершения = Новый ОписаниеОповещения("ПослеВыбораИзСправочника", ЭтаФорма);
        ОткрытьФорму("Справочник.Подразделения.ФормаВыбора", ПараметрыВыбора, ЭтаФорма, , , , ОписаниеЗавершения);
    ИначеЕсли ВыбранныйЭлемент.Значение = "Клиент" Тогда
        // Логика для выбора клиента (строки)
        Объект.Источник = "Тип: Клиент";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораИзСправочника(Результат, Параметры) Экспорт
    Если Результат <> Неопределено Тогда
        Объект.Источник = Результат;
    КонецЕсли;
КонецПроцедуры

Этот подход более «чистый» с точки зрения архитектуры 1С, так как он разделяет процесс выбора категории и процесс получения конкретной ссылки. Обратите внимание, что при таком способе нам не нужно вручную манипулировать свойством ОграничениеТипа в большинстве случаев, так как мы напрямую записываем результат выбора в реквизит.

Типичные ошибки при работе с формой

Проанализируем ситуацию из сообщения 4 в исходной теме. Автор пытался использовать методы ЭтаФорма.Записать() и ЭтаФорма.Прочитать() для обновления данных. Это крайне не рекомендуется делать для решения проблем визуального отображения по следующим причинам:

Рекомендации по работе со списками выбора

Если вы все же решили использовать СписокВыбора (ChoiceList) для составного типа, придерживайтесь следующих правил:

  1. При программном изменении значения всегда проверяйте, есть ли это значение в Элементы.ИмяРеквизита.СписокВыбора.
  2. Если вы хотите, чтобы пользователь мог вводить и текст, и выбирать из списка, установите РежимВыбораИзСписка = Ложь, но при этом заполняйте СписокВыбора для подсказок.
  3. Используйте метод ПривестиЗначение() объекта ОписаниеТипов, если вы не уверены в чистоте типа данных перед присвоением:
    
    Описание = Новый ОписаниеТипов("СправочникСсылка.Подразделения");
    Объект.Источник = Описание.ПривестиЗначение(ПолученноеЗначение);
    

Выяснив причину конфликта между данными и их представлением на форме, мы можем сделать вывод: стабильная работа составных типов требует синхронного управления как самим значением реквизита Объект, так и свойствами отображения элемента Элементы. Следуя описанным выше шагам, вы сможете добиться корректного поведения интерфейса в любых сложных сценариях заполнения данных.

← На главную