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