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