Как обновить значения элементов обычной формы при программном изменении объекта в 1С?

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

При разработке обработок в режиме обычных форм разработчики нередко сталкиваются с ситуацией, когда в реквизит формы помещается объект прикладного типа (например, ДокументОбъект), а его реквизиты выводятся напрямую на форму через свойство Данные. Если такой объект модифицируется программно — например, в модуле объекта, в модуле формы или внутри обработчика, подключенного через ПодключитьОбработчикИзмененияДанных, — значения в элементах управления на форме могут остаться прежними. Метод ЭтаФорма.Обновить() в этом случае не приводит к перерисовке значений элементов.

Разберем детально, почему так происходит, какие особенности платформы 1С влияют на этот механизм и как гарантированно актуализировать отображение данных на форме.

Почему не происходит автоматическое обновление элементов формы

Проанализируем основные причины, из-за которых элементы управления обычной формы перестают синхронизироваться с измененным объектом:

  1. Особенности связывания данных для неосновных объектов. В обычных формах автоматическая двусторонняя синхронизация (data binding) надежно работает для основного реквизита формы (например, самого документа в его родной форме). Если же экземпляр типа ДокументОбъект хранится как произвольный реквизит формы обработки, платформа не всегда автоматически отслеживает изменение его внутренних полей, чтобы обновить свойство Значение у связанных элементов управления.
  2. Блокировка контекста в обработчике изменения данных. При выполнении процедур, назначенных через ПодключитьОбработчикИзмененияДанных, платформа предотвращает возникновение бесконечной рекурсии (зацикливания событий изменения данных). В этот момент каскадные события интерфейсного обновления могут временно подавляться.
  3. Назначение метода ЭтаФорма.Обновить(). Данный метод выполняет лишь перерисовку графической составляющей формы и пересчет табличных полей, но не производит принудительное перечитывание свойств произвольных объектов в элементы интерфейса.

Способ 1. Программный обход и синхронизация элементов формы

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


Процедура ОбновитьЗначенияЭлементовФормыПоОбъекту(ЭлементыФормы, ИмяОбъекта, ЗначениеОбъекта, ПропускатьТабличныеЧасти = Истина) Экспорт
    
    Для Каждого ЭлементФормы Из ЭлементыФормы Цикл
        
        Если ПустаяСтрока(ЭлементФормы.Данные) Тогда
            Продолжить;
        КонецЕсли;    
        
        МассивПути = ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(ЭлементФормы.Данные, ".", Истина);
        
        Если МассивПути.Количество() < 2 Тогда
            Продолжить;
        КонецЕсли;    
        
        // Проверяем, что элемент привязан именно к нашему объекту
        Если МассивПути[0] <> ИмяОбъекта Тогда
            Продолжить;
        КонецЕсли;    
        
        // Обработка табличных полей
        Если ТипЗнч(ЭлементФормы) = Тип("ТабличноеПоле") Тогда
            Если Не ПропускатьТабличныеЧасти Тогда
                ЭлементФормы.ОбновитьСтроки();
            КонецЕсли;    
        Иначе
            // Обработка обычных полей ввода и элементов управления
            Если МассивПути.Количество() = 2 Тогда
                ЭлементФормы.Значение = ЗначениеОбъекта[МассивПути[1]];
            Иначе
                // Обработка составных путей к данным через точку
                Путь = "";
                Для ИндексМассива = 2 По МассивПути.ВГраница() Цикл
                    Путь = Путь + "." + МассивПути[ИндексМассива];
                КонецЦикла;    
                Путь = Сред(Путь, 2);
                ЭлементФормы.Значение = ОбщегоНазначения.ПолучитьЗначениеРеквизита(ЗначениеОбъекта[МассивПути[1]], Путь);
            КонецЕсли;
        КонецЕсли;    
        
    КонецЦикла; 
    
КонецПроцедуры

Разберем принцип работы данного кода:

  1. Мы перебираем коллекцию ЭлементыФормы и анализируем путь к данным в свойстве Данные.
  2. С помощью строковых функций определяем, начинается ли путь с имени нашего реквизита-объекта (например, "ДокОбъект.ДоговорКонтрагента").
  3. Для табличных полей вызываем метод ОбновитьСтроки(), а для остальных элементов управления явно присваиваем свойству Значение актуальные данные из памяти объекта.

Способ 2. Разрыв контекста через обработчик ожидания

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

Посмотрим на пример организации вызова:


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

Процедура СинхронизироватьДанныеПослеИзменения()
    // Здесь выполняем необходимые изменения в объекте и интерфейсе
    ДокОбъект.ДоговорКонтрагента = ПолучитьДоговорПоУмолчанию(ДокОбъект.Контрагент);
    ЭлементыФормы.ДоговорКонтрагента.Значение = ДокОбъект.ДоговорКонтрагента;
КонецПроцедуры

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

Способ 3. Использование предопределенного события «ОбновлениеОтображения»

В обычных формах предусмотрено штатное событие формы ОбновлениеОтображения. Оно вызывается платформой при любых изменениях состояния элементов, переключении фокуса или интерактивных действиях.

Рассмотрим, как его задействовать:


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

Такой подход позволяет вынести логику визуальной синхронизации в единое место модуля формы без необходимости дублирования кода в каждом локальном событии.

Альтернативные архитектурные решения

Если форма обработки перегружена сложными зависимостями документа, стоит рассмотреть альтернативные варианты архитектуры:

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