Почему реквизиты управляемой формы имеют жесткий тип и как правильно передавать ссылки в параметры открытия формы?

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

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

Природа реквизитов управляемой формы: ДанныеФормы

Для начала проанализируем, чем реквизит формы отличается от обычной переменной в коде. Когда мы объявляем переменную внутри процедуры (например, Подарок = Справочники.Подарки.ПустаяСсылка();), мы имеем дело с динамической типизацией. В такую переменную можно сначала записать ссылку, потом число, а затем строку. Платформа 1С позволяет это делать без ограничений.

Однако реквизит формы — это не просто переменная. Это часть сложной структуры под названием ДанныеФормы. Рассмотрим ключевые отличия:

  1. Статическая типизация в метаданных: Тип реквизита формы жестко задается в редакторе формы. Это необходимо платформе для оптимизации памяти и работы интерфейса.
  2. Сериализация: Управляемое приложение работает по принципу «тонкого клиента». Данные постоянно перемещаются между сервером и клиентом. Чтобы передать реквизит с сервера на клиент, платформа должна его «сериализовать» — упаковать в специальный формат. Для этого ей заранее нужно знать, какой объем данных и какого типа будет передаваться.
  3. Связь с элементами интерфейса: Реквизиты часто связаны с элементами формы (полями ввода, надписями). Чтобы поле ввода понимало, нужно ли показывать кнопку выбора или кнопку открытия, оно должно знать тип данных реквизита еще до того, как в него что-то запишут.

Разбор практического примера

Рассмотрим ситуацию, описанную в вопросе. У нас есть процедура на сервере, которая ищет самый дорогой подарок и пытается сохранить ссылку на него в реквизит формы СсылкаНаПодарок.


&НаСервере
Процедура ПоискНаСервере()
    
    Менеджер = Справочники.Подарки;
    Выборка = Менеджер.Выбрать();
    
    Цена = 0;
    Подарок = Справочники.Подарки.ПустаяСсылка();
    
    Пока Выборка.Следующий() Цикл
        Если Выборка.Цена > Цена Тогда
            Цена = Выборка.Цена;
            Подарок = Выборка.Ссылка;    
        КонецЕсли; 
    КонецЦикла; 
    
    Элементы.НадписьПодарок.Заголовок = Подарок.Наименование;
    Элементы.НадписьЦена.Заголовок = Цена;
    
    // В этот момент происходит проверка типов
    СсылкаНаПодарок = Подарок;
    
КонецПроцедуры

Выясним причину, почему код СсылкаНаПодарок = Подарок может не сработать. Если в редакторе формы для СсылкаНаПодарок указан тип СправочникСсылка.Сотрудники, а мы пытаемся записать туда СправочникСсылка.Подарки, платформа выполнит неявное приведение типов. Поскольку типы несовместимы, система запишет в реквизит пустую ссылку того типа, который указан в настройках реквизита. Именно поэтому автор вопроса видел «пустое» значение.

Механизм работы параметра «Ключ»

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


&НаКлиенте
Процедура НадписьПодарокНажатие(Элемент)
    
    // ПараметрыФормы — это структура
    ПараметрыФормы = Новый Структура("Ключ", СсылкаНаПодарок);
    
    // Открываем форму конкретного справочника
    ОткрытьФорму("Справочник.Подарки.ФормаОбъекта", ПараметрыФормы);
    
КонецПроцедуры

Разберем по шагам, что происходит внутри метода ОткрытьФорму:

  1. Платформа получает команду открыть форму справочника Подарки.
  2. Она видит в структуре параметров ключ "Ключ". Для платформы это сигнал: «нужно открыть форму конкретного, уже существующего в базе данных элемента».
  3. Система берет значение из этого ключа и пытается найти объект в таблице Справочник.Подарки.
  4. Если в СсылкаНаПодарок лежит ссылка другого типа (например, СправочникСсылка.Сотрудники), механизм поиска объекта не сможет сопоставить ее с таблицей подарков.
  5. Результат: Форма откроется либо как для создания нового элемента (пустая), либо выдаст ошибку о неверных параметрах.

Как обойти жесткую типизацию?

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

Способ 1: Составной тип данных

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

Способ 2: Тип «Произвольный»

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

Во-первых, такой реквизит нельзя использовать как «Путь к данным» для элементов формы, предназначенных для редактирования ссылок. Вы не сможете привязать к нему поле ввода и ожидать, что там появится кнопка выбора (три точки) или кнопка открытия (лупа), так как платформа не знает, какой список выбора предлагать пользователю.

Во-вторых, не все данные типа Произвольный могут быть переданы с сервера на клиент. Объекты, которые существуют только на сервере (например, Запрос, ВыборкаИзРезультатаЗапроса, ЗаписьXML), невозможно сериализовать. Если вы попытаетесь записать их в произвольный реквизит формы и закончить серверный вызов, вы получите ошибку выполнения.

Рекомендации по передаче параметров

Проанализируем ситуацию: если ваша цель — просто передать какую-то информацию из одной формы в другую (например, из формы поиска в форму объекта), не обязательно создавать для этого типизированные реквизиты на форме-отправителе.

Мы можем использовать временные структуры. Рассмотрим пример передачи данных напрямую:


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

В открываемой форме в процедуре ПриСозданииНаСервере эти данные будут доступны в коллекции Параметры. Там они сохраняют свой исходный тип, так как передаются в рамках одного сеанса инициализации формы. Это позволяет избежать проблем с предварительной типизацией реквизитов формы.

Итоги

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

← На главную