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