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