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