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