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