Кто открыл форму: ВладелецФормы, Родитель и передача данных в 1С 8.3

· 9 мин

Содержание

Владельца управляемой формы в 1С 8.3 определяют через свойство формы ВладелецФормы. В клиентском коде открытой формы оно возвращает тот объект, который передали третьим параметром в ОткрытьФорму(): другую форму, элемент формы (поле, таблицу) или Неопределено, если владельца не задали. Отдельной функции Владелец() в языке нет — это частая путаница с реквизитом Владелец подчинённого справочника.

Способов «узнать, откуда пришли» несколько. ВладелецФормы подходит, когда форма открыта из кода с явным владельцем. Параметры формы надёжнее, если данные нужны на сервере. ОписаниеОповещения выбирают, когда важно вернуть результат обратно, а не просто знать вызывающего.

Как устроена иерархия форм и элементов

В управляемой форме есть две разные «родословные», и их легко перепутать.

  • 🪟 Связь форма → форма. Одна форма открыла другую и стала её владельцем. Эту связь хранит свойство ВладелецФормы открытой формы.
  • 🌳 Дерево элементов внутри формы. Поле лежит в группе, группа — в другой группе или прямо на форме. Эту связь хранит свойство Родитель у каждого элемента.
  • 📁 Иерархия данных. Справочник может быть подчинён другому (договоры подчинены контрагентам) — тогда у объекта есть реквизит Владелец. Если справочник иерархический — есть реквизит Родитель (группа). К формам это отношения не имеет.

Владельцем формы бывает:

Что передали в ОткрытьФорму()Тип ВладелецФормыТипичный случай
ЭтаФормаФормаКлиентскогоПриложенияОткрыли форму обработки из документа
Элементы.КонтрагентПолеФормыОткрыли свою форму выбора для поля
Элементы.ТоварыТаблицаФормыПодбор в табличную часть
НичегоНеопределеноОткрыли из командного интерфейса или по ссылке

До платформы 8.3.14 тип формы назывался УправляемаяФорма. В новых релизах основное имя — ФормаКлиентскогоПриложения. В коде, который должен работать на разных платформах, проверяйте тип так, как принято в вашей конфигурации.

Свойство ВладелецФормы: как получить владельца формы

Свойство читается из клиентского кода открытой формы: в обработчике ПриОткрытии, в командах, в обработчиках событий элементов.

&НаКлиенте
Процедура ПриОткрытии(Отказ)

	Если ВладелецФормы = Неопределено Тогда
		Сообщить("Форма открыта без владельца");
		Возврат;
	КонецЕсли;

	Если ТипЗнч(ВладелецФормы) = Тип("ФормаКлиентскогоПриложения") Тогда
		Сообщить("Владелец — форма " + ВладелецФормы.ИмяФормы);
	Иначе
		Сообщить("Владелец — элемент " + ВладелецФормы.Имя);
	КонецЕсли;

КонецПроцедуры

Что важно знать о свойстве:

  • 🔹 Только клиент. На сервере, в том числе в ПриСозданииНаСервере, владелец недоступен: на сервер передаётся контекст только текущей формы. Нужные серверу данные передавайте через параметры (раздел ниже).
  • 🔹 Значение задаётся при открытии. Форма, открытая из панели разделов или по навигационной ссылке, владельца не получает.
  • 🔹 ИмяФормы — полное имя. Например, Документ.ПоступлениеТоваровУслуг.Форма.ФормаДокумента. По нему удобно понять, из какого объекта пришли.
  • 🔹 Владелец влияет на поведение окна. При режиме БлокироватьОкноВладельца блокируется именно окно владельца. Без владельца блокировать нечего.

Как определить форму, если владелец — элемент

Когда в ОткрытьФорму() передали поле, ВладелецФормы вернёт поле, а не форму. Чтобы добраться до формы, поднимайтесь по свойству Родитель: у элемента верхнего уровня родителем будет сама форма.

&НаКлиенте
Функция ФормаВладельца(Форма)

	Владелец = Форма.ВладелецФормы;

	Пока Владелец <> Неопределено
		И ТипЗнч(Владелец) <> Тип("ФормаКлиентскогоПриложения") Цикл
		Владелец = Владелец.Родитель;
	КонецЦикла;

	Возврат Владелец;

КонецФункции

Цикл конечен: дерево элементов всегда заканчивается формой. Если владельца нет, функция вернёт Неопределено — проверяйте результат перед обращением к реквизитам.

Пример использования: форма проверки должна понять, открыли её из документа или из другого места.

&НаКлиенте
Процедура ПриОткрытии(Отказ)

	Форма = ФормаВладельца(ЭтаФорма);
	Если Форма <> Неопределено
		И СтрНачинаетсяС(Форма.ИмяФормы, "Документ.") Тогда
		Сообщить("Открыто из документа: " + Форма.ИмяФормы);
	КонецЕсли;

КонецПроцедуры

Сами реквизиты документа так брать не стоит — для этого есть параметры, о них ниже.

Владелец и Родитель: в чём разница

Обе связи ведут «вверх», но по разным деревьям.

ВладелецФормыРодитель
У кого естьУ формыУ элемента формы (поле, группа, таблица, кнопка)
Что возвращаетФорму или элемент, который открыл текущую формуГруппу или форму, внутри которой лежит элемент
Когда задаётсяВ момент открытия формыВ конфигураторе или при Элементы.Добавить() / Элементы.Переместить()
Может быть пустымДа, НеопределеноНет, у элемента всегда есть родитель
Зачем нуженСвязь между окнами, выбор, блокировка окнаПостроение и перестройка внешнего вида формы

А теперь про данные. Объект.Владелец в форме элемента справочника «Договоры контрагентов» — это контрагент. Объект.Родитель в форме номенклатуры — группа, в которой лежит позиция. Это реквизиты объекта, а не связь окон.

Если в коде формы договора написать ВладелецФормы, вы получите форму, откуда открыли договор. Контрагента там нет. Нужен контрагент — берите Объект.Владелец.

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

Владельца задают третьим параметром ОткрытьФорму(). Тот же порядок параметров у ПолучитьФорму().

&НаКлиенте
Процедура ОткрытьПроверку(Команда)

	ПараметрыФормы = Новый Структура("Контрагент", Объект.Контрагент);

	ОткрытьФорму("Обработка.ПроверкаКонтрагента.Форма",
		ПараметрыФормы,
		ЭтаФорма,           // владелец
		,                   // уникальность
		,                   // окно
		,                   // навигационная ссылка
		,                   // оповещение о закрытии
		РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);

КонецПроцедуры

Что выбрать владельцем:

  1. ЭтаФорма — если открытая форма работает с документом в целом: проверка, печать, сервисная обработка.
  2. Элемент формы — если форма заменяет стандартный выбор для конкретного поля. Тогда результат выбора сам придёт в это поле.
  3. Ничего — если форма независима и не должна знать, кто её вызвал.

Выбор значения через владельца

Владелец нужен в механизме выбора. Подчинённая форма вызывает ОповеститьОВыборе(Значение), и платформа передаёт значение владельцу:

  • если владелец — поле формы, значение попадает в поле, срабатывает его событие ОбработкаВыбора;
  • если владелец — форма, вызывается обработчик формы ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора).
// В подчинённой форме
&НаКлиенте
Процедура Выбрать(Команда)
	ОповеститьОВыборе(Элементы.Список.ТекущиеДанные.Ссылка);
КонецПроцедуры

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

Параметр ИсточникВыбора — это подчинённая форма. По её ИмяФормы владелец различает, откуда пришло значение, если подборов несколько. Закрывать ли окно после выбора, решает свойство ЗакрыватьПриВыборе.

Без владельца ОповеститьОВыборе никуда значение не передаст — форма просто закроется (или останется открытой), а поле не заполнится.

Передача данных между формами: параметры вместо владельца

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

Надёжнее передавать всё нужное через параметры.

  1. В конфигураторе откройте форму, перейдите на вкладку Параметры и добавьте параметр, например Организация с типом СправочникСсылка.Организации.
  2. При открытии передайте значение в структуре: Новый Структура("Организация", Объект.Организация).
  3. В ПриСозданииНаСервере прочитайте Параметры.Организация. Параметры доступны и на сервере, в отличие от ВладелецФормы.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	Если Не ЗначениеЗаполнено(Параметры.Организация) Тогда
		Отказ = Истина;
		Возврат;
	КонецЕсли;

	Организация = Параметры.Организация;

КонецПроцедуры

Отбор по владельцу справочника при открытии формы выбора

Здесь «владелец» — уже реквизит данных, но задачу часто ищут теми же словами. Пример: нужно открыть выбор договора только по контрагенту из документа. Отбор передают в параметре Отбор, а форму-владельца — третьим параметром, чтобы выбранное значение вернулось в поле.

&НаКлиенте
Процедура ДоговорНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)

	СтандартнаяОбработка = Ложь;

	Отбор = Новый Структура("Владелец", Объект.Контрагент);
	ПараметрыФормы = Новый Структура("Отбор, РежимВыбора", Отбор, Истина);

	ОткрытьФорму("Справочник.ДоговорыКонтрагентов.ФормаВыбора",
		ПараметрыФормы, Элемент);

КонецПроцедуры

Главное здесь — третий параметр: владельцем стал сам элемент Договор. После выбора строки значение само попадёт в поле, отдельный ОбработкаВыбора писать не нужно.

Для простых случаев код не нужен. В свойствах поля в конфигураторе есть «Связи параметров выбора»: укажите Отбор.Владелец и путь к реквизиту Объект.Контрагент. Платформа сама наложит отбор при выборе.

Внутри формы выбора владельца-поле тоже можно прочитать. ВладелецФормы.Имя вернёт имя поля, например Договор. Это помогает, если одна форма выбора обслуживает несколько полей и должна вести себя по-разному.

Вернуть результат без ВладелецФормы

Для возврата данных в современном коде используют ОписаниеОповещения. Вызывающая форма передаёт его седьмым параметром ОткрытьФорму(), подчинённая закрывается методом Закрыть(Результат).

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

&НаКлиенте
Процедура ПослеВводаСуммы(Результат, ДополнительныеПараметры) Экспорт
	Если Результат <> Неопределено Тогда
		Объект.СуммаДокумента = Результат;
	КонецЕсли;
КонецПроцедуры

// Подчинённая форма
&НаКлиенте
Процедура ОК(Команда)
	Закрыть(Сумма);
КонецПроцедуры

Если пользователь закрыл окно крестиком, Результат придёт как Неопределено. Это и проверяет условие в обработчике.

Какой способ выбрать

ЗадачаЧем решать
Узнать на клиенте, кто открыл формуВладелецФормы
Получить данные на сервере при создании формыПараметры
Выбрать значение в полеВладелец-элемент + ОповеститьОВыборе
Вернуть результат и продолжить кодОписаниеОповещения + Закрыть(Результат)
Сообщить всем открытым формам об измененииОповестить() и ОбработкаОповещения
Узнать форму, где нажали общую командуПараметрыВыполненияКоманды.Источник

Последняя строка — частая находка. В обработчике общей команды ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды) свойство Источник содержит форму, из которой выполнили команду. Там владельца ещё нет — форма только будет открыта, — и Источник удобно передать в ОткрытьФорму() как владельца.

&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
	ОткрытьФорму("Обработка.Сверка.Форма",
		Новый Структура("Основание", ПараметрКоманды),
		ПараметрыВыполненияКоманды.Источник);
КонецПроцедуры

Обычные формы и толстый клиент

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

Форма = ПолучитьФорму("ФормаПодбора");
Форма.ВладелецФормы = ЭтаФорма;
Форма.Открыть();

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

Ошибки при обращении к владельцу формы и отладка

Диагностика: выберите симптом

Как посмотреть владельца в отладчике:

  1. Поставьте точку останова в ПриОткрытии подчинённой формы.
  2. Запустите отладку и откройте форму так же, как это делает пользователь.
  3. Выделите в коде ВладелецФормы и вычислите выражение (Shift+F9). Раскройте значение: видно тип и свойства.
  4. Для проверки типа вычислите ТипЗнч(ВладелецФормы), для имени — ВладелецФормы.ИмяФормы.

Добавьте ВладелецФормы в табло отладчика. Тогда при каждой остановке не придётся вычислять выражение заново.

Если форма открывается из типовой конфигурации и владелец неожиданный, найдите место вызова. Воспользуйтесь глобальным поиском в конфигураторе по имени формы, например "Обработка.ПроверкаКонтрагента.Форма". Третий параметр в найденном ОткрытьФорму() и есть будущий владелец.

Частые вопросы

Можно ли получить владельца владельца?
Да. ВладелецФормы.ВладелецФормы вернёт форму, которая открыла владельца. Но если по пути встретится элемент, сначала поднимитесь по Родитель до формы.
Как узнать уникальный идентификатор формы-владельца?
Найдите форму-владелец и прочитайте её свойство УникальныйИдентификатор. Он пригодится для ПоместитьВоВременноеХранилище, чтобы данные жили, пока открыт владелец.
Можно ли проверить владельца в форме, которую открывает типовой код?
Да, если форма ваша или вы меняете её через расширение. Добавьте в расширении обработчик ПриОткрытии и прочитайте ВладелецФормы там, не трогая основную конфигурацию.
Работает ли ВладелецФормы в веб-клиенте?
Да. Свойство клиентское, в тонком и веб-клиенте код из этой статьи работает одинаково.
Чем ВладелецФормы отличается от ЭтотОбъект?
ЭтотОбъект и ЭтаФорма в коде формы указывают на текущую форму. ВладелецФормы — на ту, что её открыла.