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