Как определить владельца формы выбора в 1С и передать параметры отбора

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

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

Понимание архитектуры владельца формы

Прежде чем переходить к коду, давайте проанализируем, что такое ВладелецФормы. В системе 1С владельцем открываемой формы выбора не всегда является сама форма документа. Если выбор инициирован из поля ввода, то свойство ВладелецФормы будет содержать ссылку на элемент управления (ПолеВвода). Чтобы добраться до данных самого документа, нам придется «подниматься» выше по иерархии родителей или обращаться к свойствам этого элемента.

Ситуация осложняется, когда мы работаем с табличным документом. В этом случае стандартная событийная модель может не заполнять владельца автоматически так, как нам ожидается. Рассмотрим основные стратегии решения этой задачи.

Решение 1: Универсальный поиск владельца по типу (для управляемых и обычных форм)

Одним из самых надежных способов является написание универсальной функции, которая будет рекурсивно или в цикле обходить иерархию владельцев и родителей до тех пор, пока не найдет объект нужного нам типа (например, ссылку на документ). Рассмотрим реализацию такой функции, которая последовательно проверяет наличие свойств Объект, ВладелецФормы и Родитель.


// Функция ищет владельца переданной клиентской формы
// Возвращает: Ссылка на найденный объект или Неопределено
Function НайтиОбъектВладелецФормы(Форма) Экспорт
    Попытка
        ОбъектПоиска = Форма.ВладелецФормы;
    Исключение
        Возврат Неопределено;
    КонецПопытки;

    Пока Истина Цикл
        // Пытаемся найти ссылку на объект-владелец
        Попытка
            // В управляемых формах данные часто лежат в реквизите "Объект"
            Результат = ОбъектПоиска.Объект.Ссылка;
            Возврат Результат;
        Исключение
            // Если ссылки нет, пробуем искать владельца текущего элемента
            Попытка
                ОбъектПоиска = ОбъектПоиска.ВладелецФормы;
            Исключение
                // Если владельца нет, пробуем обратиться к родителю
                Попытка
                    ОбъектПоиска = ОбъектПоиска.Родитель;
                Исключение
                    // Если достигли конца иерархии, прерываем поиск
                    Возврат Неопределено;
                КонецПопытки;
            КонецПопытки;
        КонецПопытки;
        
        // Дополнительная проверка на зацикливание или пустое значение
        Если ОбъектПоиска = Неопределено Тогда
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Неопределено;
EndFunction

Рассмотрим, как это работает: программа берет текущего владельца формы и начинает «простукивать» его структуру. Мы используем блоки Попытка...Исключение, так как на разных уровнях иерархии (элемент формы, форма, расширение формы) набор доступных свойств различается (в таких случаях может помочь получение значения реквизита по ссылке). Этот метод позволяет найти «корневой» документ, даже если форма выбора была вызвана из глубоко вложенной подсистемы.

Решение 2: Использование жесткой цепочки родителей

Если структура вашей конфигурации стабильна и вы точно знаете, из какой формы и при каких условиях открывается справочник, можно использовать прямой путь. Проанализируем пример для конфигурации «Бухгалтерия предприятия» (Обычные формы), где форма выбора открывается из табличной части документа:

В коде формы выбора (в процедуре ПриОткрытии) можно обратиться к данным следующим образом:


// Пример получения ссылки на документ "Отчет производства за смену"
// Путь может варьироваться в зависимости от вложенности элементов
ОбъектДокумента = ВладелецФормы.Родитель.Родитель.Родитель.Объект.Ссылка;

Важный момент: такой способ крайне хрупок. Если вы добавите на форму документа еще одну панель или перенесете поле ввода в другую группу, количество «родителей» изменится, и код перестанет работать. Мы рекомендуем использовать Решение 1 как более гибкое.

Решение 3: Передача параметров через структуру отбора

Чтобы не заниматься «расследованием» внутри самой формы выбора, мы можем применить правильный подход к самому моменту открытия формы (например, используя отбор СКД по табличной части или таблице значений на управляемой форме). Если мы инициируем выбор из ячейки табличного документа, нам необходимо программно сформировать параметры.

Проанализируем алгоритм действий:

  1. В событии Выбор или ОбработкаРасшифровки табличного документа мы получаем значение нужного нам учреждения из текущего контекста (строки или реквизита формы).
  2. Формируем структуру отбора.
  3. Передаем её при открытии формы выбора.

Пример кода для программного открытия формы выбора с предустановленным фильтром (хотя иногда удобнее открыть форму внутри другой формы):


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

Особенности работы в обычных формах (8.1 и 8.2)

В обычных формах свойство ВладелецФормы доступно не всегда сразу или может вести себя специфично. Выясним важную деталь: если форма открывается модально или через ВыбратьИзСписка, контекст может быть ограничен. Для платформы 1С 8.1 часто используется обращение через ЭтаФорма, чтобы гарантировать доступ к свойствам текущего контекста.

Если вы все же решили определять владельца внутри ПриОткрытии формы выбора, помните, что на сервере ВладелецФормы может быть недоступен. Проанализируем пример разделения логики:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // В управляемом приложении работаем через ВладелецФормы
    Если ВладелецФормы <> Неопределено Тогда
        // Копируем данные из формы владельца в локальный реквизит для работы на сервере
        КопироватьДанныеФормы(ВладелецФормы.Объект, ИсточникФормы);
    КонецЕсли;
КонецПроцедуры

Механизм «Связи параметров выбора»

Не стоит забывать про встроенный механизм платформы Связи параметров выбора (ChoiceParameterLinks) — для этой задачи есть автоматизация настроек интерфейса и поиска 1С. Хотя автор темы искал программный способ, для большинства задач с реквизитами объектов это лучшее решение. Рассмотрим, как оно работает:

Система сама применит отбор, и вам не придется писать ни одной строки кода для определения владельца. Однако, для табличных документов (как в исходном вопросе) этот метод напрямую не применим, так как ячейка таблицы не является реквизитом объекта метаданных с предустановленными связями.

Выводы и рекомендации

Проанализировав ситуацию, мы можем подвести итог. Если вам нужно определить владельца формы выбора:

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

Помните, что архитектура 1С стремится к минимизации прямой зависимости форм друг от друга. Старайтесь проектировать взаимодействие так, чтобы форма выбора получала все необходимые данные для своей работы в виде готовых параметров при открытии.

← На главную