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