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