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