Как обновлять данные в форме при использовании ОписаниеОповещения вместо модальных окон?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Переход с модального режима на асинхронную модель работы — одна из самых частых задач при адаптации конфигураций 1С под веб-клиент или современные требования платформы 8.3. В модальном режиме выполнение кода останавливалось, и при повторном вызове форма всегда создавалась заново. Однако использование ОписаниеОповещения меняет логику: если форма уже открыта, система может просто активировать существующее окно, и привычная процедура ПриСозданииНаСервере не сработает. Рассмотрим, как правильно управлять обновлением данных в таких сценариях.

Проблема: Почему форма не обновляется?

Когда мы используем метод ОткрытьФорму без указания специальных параметров, платформа 1С пытается найти уже открытый экземпляр этой формы для данного владельца. Если такая форма найдена, она просто выводится на передний план. Поскольку объект формы не создается заново, серверное событие ПриСозданииНаСервере не вызывается. В результате пользователь видит старые данные, которые были актуальны при первом открытии окна.

Разберем ситуацию на примере автора темы: при нажатии на номенклатуру открывается форма со списком характеристик. Если пользователь сначала открыл характеристики одного товара, а затем, не закрывая окно, нажал на другой товар — форма останется прежней.

Вариант 1. Использование ключа уникальности (Рекомендуемый способ)

Самый простой и эффективный способ заставить платформу каждый раз создавать новый экземпляр формы — это использование параметра КлючУникальности. Если передать туда уникальное значение, система не найдет «старую» форму и будет вынуждена инициировать процедуру создания заново.

Проанализируем пример кода, который решает задачу «в лоб»:


ПараметрыФормы = Новый Структура("Номенклатура", ВыбраннаяНоменклатура);
УникальныйКлюч = Новый УникальныйИдентификатор();

ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗакрытияФормыХарактеристик", ЭтотОбъект);

ОткрытьФорму("Справочник.Номенклатура.Форма.ФормаХарактеристик", 
             ПараметрыФормы, 
             ЭтотОбъект, 
             УникальныйКлюч, 
             , 
             , 
             ОписаниеОповещения);

В этом случае при каждом вызове будет создаваться новое окно, и процедура ПриСозданииНаСервере отработает штатно, заполнив форму актуальными данными на основании переданных параметров.

Вариант 2. Обработка события «ПриПовторномОткрытии»

Если ваша задача — не плодить множество окон, а использовать одно и то же окно, обновляя в нем информацию, то следует использовать стандартный обработчик события ПриПовторномОткрытии. Это событие вызывается на клиенте именно тогда, когда система нашла уже открытую форму.

Рассмотрим алгоритм реализации этого метода:

  1. В вызывающей форме мы передаем новые данные через структуру Параметры.
  2. В открываемой форме создаем процедуру-обработчик ПриПовторномОткрытии.
  3. Внутри этой процедуры анализируем новые параметры и вызываем серверный метод для обновления данных.

Пример кода в открываемой форме:


&НаКлиенте
Процедура ПриПовторномОткрытии(СтандартнаяОбработка)
    // Извлекаем новые параметры, переданные при вызове ОткрытьФорму
    НоваяНоменклатура = Параметры.Номенклатура;
    
    // Вызываем серверную процедуру для пересчета цен или обновления списка
    ОбновитьДанныеНаСервере(НоваяНоменклатура);
КонецПроцедуры

&НаСервере
Процедура ОбновитьДанныеНаСервере(Знач НоваяНоменклатура)
    // Здесь логика, которая ранее была в ПриСозданииНаСервере
    Объект.Номенклатура = НоваяНоменклатура;
    СформироватьСписокХарактеристик();
КонецПроцедуры

Вариант 3. Принудительное закрытие старых окон (Метод автора)

Автор темы предложил решение через перебор всех открытых окон приложения. Мы не рекомендуем использовать этот метод как основной, так как он ресурсозатратный и зависит от заголовков окон, которые могут меняться. Однако для понимания того, как это работает «под капотом», разберем этот пример.

Суть заключается в том, чтобы программно найти окно с определенным заголовком и закрыть его перед открытием нового:


Окна = ПолучитьОкна();
Для Каждого Окно Из Окна Цикл
    Если Окно.Заголовок = "Характеристики и цена номенклатуры" Тогда
        ФормаХарЦен = Окно.ПолучитьСодержимое();
        Если ФормаХарЦен <> Неопределено Тогда
            ФормаХарЦен.Закрыть();
        КонецЕсли;
    КонецЕсли;    
КонецЦикла;

// Теперь вызываем открытие формы - она точно создастся с нуля
ОткрытьФорму("ИмяФормы", ПараметрыФормы, , , , , ОписаниеОповещения);

Важный нюанс: Поиск по заголовку — это «хрупкое» решение. Если в конфигурации включено отображение артикула или кода в заголовке, ваш код перестанет работать. Лучше использовать КлючУникальности.

Вариант 4. Оповещение родительской формы о результатах

Часто проблема заключается не только в открытии формы, но и в возврате данных обратно. Поскольку ОписаниеОповещения работает асинхронно, основная форма должна уметь «слушать» то, что ей скажет дочернее окно. Для этого используется метод Закрыть() с параметром.

В дочерней форме (например, при выборе характеристики):


&НаКлиенте
Процедура ВыбратьИЗакрыть(Команда)
    СтруктураРезультата = Новый Структура("Характеристика, Цена", ТекущаяХарактеристика, ТекущаяЦена);
    Закрыть(СтруктураРезультата); // Данные уходят в ОписаниеОповещения
КонецПроцедуры

В родительской форме (процедура обратного вызова):


&НаКлиенте
Процедура ПослеЗакрытияФормыХарактеристик(Результат, ДополнительныеПараметры) Экспорт
    Если Результат <> Неопределено Тогда
        // Обрабатываем полученные данные
        ТекущаяСтрока.Характеристика = Результат.Характеристика;
        ТекущаяСтрока.Цена = Результат.Цена;
    КонецЕсли;
КонецПроцедуры

Механизм «ОповеститьОбИзменении»

Если формы должны синхронизироваться глобально (например, при изменении цены в одном окне она должна обновиться во всех открытых списках), используйте связку Оповестить() и ОбработкаОповещения.

  1. В форме, где данные изменились, вызываем: Оповестить("ОбновлениеЦен", НоваяЦена, СсылкаНаТовар);
  2. Во всех остальных формах создаем обработчик ОбработкаОповещения, который будет реагировать на событие с именем "ОбновлениеЦен".

Этот подход является наиболее «чистым» с точки зрения архитектуры управляемого приложения, так как он полностью избавляет формы от жесткой зависимости друг от друга.

Резюме

Выясним причину проблем с обновлением: она кроется в кэшировании окон платформой. Чтобы обойти это, используйте КлючУникальности (если нужны разные окна) или событие ПриПовторномОткрытии (если нужно одно обновляемое окно). Избегайте поиска окон по заголовкам, так как это нарушает стабильность кода при обновлении конфигурации или смене интерфейсных настроек пользователем.

← На главную