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