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