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