Как передать результат с сервера в клиент из ПриЗаписи() модуля объекта в ПослеЗаписи() управляемой формы?

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

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает задача: при записи объекта (например, справочника или документа) необходимо внести изменения в другие, связанные с ним данные, и тут же отобразить эти изменения в интерфейсе пользователя. Сложность заключается в том, что основная бизнес-логика выполняется на сервере в модуле объекта (или подписке на событие), а обновление интерфейса — это клиентская задача. Рассмотрим, как правильно организовать «сквозную» передачу данных через все уровни системы, не нарушая типовую логику и сохраняя конфигурацию на поддержке.

Постановка задачи и анализ проблемы

Представим ситуацию: у нас есть основной справочник и зависимый от него справочник. При записи основного элемента срабатывает код, который обновляет несколько записей в зависимом справочнике. Если у пользователя в этот момент открыты формы измененных зависимых элементов, он не увидит обновленные данные автоматически. Более того, при попытке редактирования он может получить ошибку о том, что объект был изменен в другой сессии. Нам нужно передать список измененных ссылок из серверного события ПриЗаписи модуля объекта в клиентское событие формы ПослеЗаписи, чтобы вызвать метод Прочитать() или оповестить систему об изменениях.

Основная техническая преграда здесь — это разрыв контекста. Свойство ДополнительныеСвойства объекта доступно только на сервере, а ВладелецФормы — только на клиенте. Решением станет использование структуры ПараметрыЗаписи, которая выступает мостом между серверными и клиентскими обработчиками формы.

Шаг 1. Сохранение данных в модуле объекта (или подписке)

Для начала проанализируем, где именно рождаются данные. В модуле объекта или в соответствующей подписке на событие ПриЗаписи мы определяем список измененных объектов. Поскольку мы не можем напрямую обратиться к форме из модуля объекта, мы используем свойство ДополнительныеСвойства. Это коллекция типа Структура, которая «путешествует» вместе с объектом в рамках одной транзакции.

Рассмотрим пример кода в подписке на событие:


Процедура _ДемоСправочникВладелецПриЗаписи(Источник, Отказ) Экспорт
    // Создаем массив для хранения ссылок на измененные зависимые элементы
    МассивСсылок = Новый Массив; 
    
    // Здесь выполняется ваша бизнес-логика по обновлению подчиненных данных.
    // Например, поиск связанных договоров или контактных лиц.
    // Заполняем массив ссылками на обновленные элементы:
    // МассивСсылок.Добавить(СсылкаНаИзмененныйОбъект);

    // Сохраняем результат в ДополнительныеСвойства объекта
    Источник.ДополнительныеСвойства.Вставить("МассивИзмененныхЭлементов", МассивСсылок);
КонецПроцедуры

Шаг 2. Переброска данных в обработчике формы ПослеЗаписиНаСервере

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

Если конфигурация находится на поддержке, мы используем механизм расширений или типовые переопределяемые модули (например, МодификацияКонфигурацииПереопределяемый):


Процедура ПослеЗаписиНаСервере(Форма, ТекущийОбъект, ПараметрыЗаписи) Экспорт
    // Проверяем, что это именно та форма, которая нам нужна
    Если Форма.ИмяФормы = "Справочник._ДемоСправочникВладелец.Форма.ФормаЭлемента" Тогда
        // Извлекаем данные из свойств объекта, которые мы положили туда в Шаге 1
        Если ТекущийОбъект.ДополнительныеСвойства.Свойство("МассивИзмененныхЭлементов") Тогда
            // Передаем данные в ПараметрыЗаписи, которые уйдут на клиент
            ПараметрыЗаписи.Вставить("МассивИзмененныхЭлементов", ТекущийОбъект.ДополнительныеСвойства.МассивИзмененныхЭлементов);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Шаг 3. Обработка данных на клиенте в ПослеЗаписи

Наконец, данные достигли клиентской части. В процедуре ПослеЗаписи на клиенте мы анализируем структуру ПараметрыЗаписи. Теперь у нас есть список ссылок, и мы можем решить, что с ними делать: обновить текущую открытую форму владельца или оповещать другие окна.

Проанализируем реализацию через механизм оповещений:


Процедура ПослеЗаписи(Форма, ПараметрыЗаписи) Экспорт
    Если Форма.ИмяФормы = "Справочник._ДемоСправочникВладелец.Форма.ФормаЭлемента" Тогда
        Если ПараметрыЗаписи.Свойство("МассивИзмененныхЭлементов") Тогда
            
            // Вариант А: Оповещение всех открытых форм конкретных объектов
            // Параметр содержит массив ссылок, которые нужно перечитать
            Оповестить("ИзменениеЗависимыхОбъектов", ПараметрыЗаписи.МассивИзмененныхЭлементов);
            
            // Вариант Б: Обновление динамических списков этого типа
            ОповеститьОбИзменении(Тип("СправочникСсылка._ДемоСправочникЗависимый"));
            
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Шаг 4. Реакция других форм на изменения

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


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

Альтернативный метод: Прямое использование ВладелецФормы

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


Если ТипЗнч(Форма.ВладелецФормы) = Тип("УправляемаяФорма") Тогда
    // Если владелец - это форма зависимого справочника, просто обновляем её
    Форма.ВладелецФормы.Прочитать();
КонецЕсли;

Важный нюанс: использование Оповестить() считается более надежным и современным подходом (Best Practice), так как оно не зависит от жесткой иерархии окон и позволяет обновить сразу несколько открытых форм, если они отображают данные, затронутые записью.

Разберем важные детали реализации

  1. Транзакционность: Помните, что код в подписке ПриЗаписи выполняется внутри транзакции. Если в процессе обновления зависимых элементов произойдет ошибка (исключение), основная запись также будет отменена. Это гарантирует целостность данных.
  2. Производительность: Если массив ссылок очень большой (тысячи элементов), передача его через ПараметрыЗаписи может вызвать кратковременное «подтормаживание» интерфейса из-за сериализации данных. В таких исключительных случаях лучше передавать только флаг необходимости обновления или адрес во временном хранилище.
  3. Расширения: Если вы используете расширения конфигурации, используйте аннотацию &После для метода ПослеЗаписиНаСервере. Это позволит вам дописать логику передачи параметров, не затрагивая основной код типового решения.

Таким образом, мы проанализировали эффективный способ связки различных уровней приложения 1С. Использование цепочки ДополнительныеСвойства -> ПараметрыЗаписи является «золотым стандартом» для передачи контекста выполнения с сервера на клиент после успешного завершения транзакции записи.

← На главную