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