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