Как заставить управляемую форму 1С перечитать и обновить данные из внешней обработки?

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

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

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

Выясняем причину: почему стандартные методы не работают

Для начала давайте разберем, почему популярные советы из интернета часто приводят к ошибкам.

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

Вторая ошибка — вызов метода Обновить() для динамического списка. Этот метод действительно перечитывает данные из базы данных. Но если пользователь еще не записал документ, а внешняя обработка изменила данные только «в оперативной памяти» формы, метод Обновить() ни к чему не приведет — из базы данных просто прочитаются старые, еще не сохраненные значения.

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

Способ 1. Использование метода КопироватьДанныеФормы (изменение в оперативной памяти)

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

Давайте разберем по шагам, как реализовать этот алгоритм в модуле формы вашей внешней обработки:


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

Теперь опишем серверную функцию, которая выполняет конвертацию данных формы в объект, производит необходимые вычисления и возвращает результат во временное хранилище:


&НаСервереБезКонтекста
Функция ИзменитьДанныеНаСервере(ДанныеФормыДокумента)
    
    // 1. Конвертируем данные формы в реальный прикладной объект
    ДокОбъект = ДанныеФормыВЗначение(ДанныеФормыДокумента, Тип("ДокументОбъект.ВедомостьНаВыплатуЗарплатыВБанк"));
    
    // 2. Производим ваши изменения в табличной части "Зарплата"
    Для Каждого СтрокаЗарплаты Из ДокОбъект.Зарплата Цикл
        // Например, корректируем выплачиваемую сумму
        СтрокаЗарплаты.КВыплате = СтрокаЗарплаты.КВыплате * 1.1; 
    КонецЦикла;
    
    // 3. Вызываем штатный пересчет ЗУП для заполнения связанных таблиц (Состав, НДФЛ и др.)
    // В зависимости от версии конфигурации это могут быть разные общие модули.
    // Например, для ведомостей часто используется следующий вызов:
    ВедомостьНаВыплатуЗарплатыФормы.ЗаполнитьНаСервере(ДокОбъект);
    
    // 4. Конвертируем объект обратно в структуру данных формы
    НовыеДанныеФормы = Новый Структура("Объект");
    // Создаем пустой макет данных формы для заполнения
    НовыеДанныеФормы.Объект = ДанныеФормыДокумента; 
    ЗначениеВДанныеФормы(ДокОбъект, НовыеДанныеФормы.Объект);
    
    // Помещаем результат во временное хранилище и возвращаем адрес
    Возврат ПоместитьВоВременноеХранилище(НовыеДанныеФормы.Объект, Новый УникальныйИдентификатор);
    
    // Альтернативный вариант (если не использовать временное хранилище) — 
    // передать данные напрямую через параметры процедуры, но использование хранилища 
    // гарантирует стабильную работу без потерь контекста.
    
ФункцияКонец

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

Способ 2. Правильный вызов метода Прочитать() (для сохраненных данных)

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

Для этого в управляемом интерфейсе предназначен метод Прочитать() объекта формы. Давайте посмотрим, как правильно вызвать этот метод, избегая ошибок контекста:


&НаКлиенте
Процедура ПеречитатьФормуВладельца()
    
    ФормаВладелец = ЭтаФорма.ВладелецФормы;
    
    Если ФормаВладелец <> Неопределено Тогда
        Попытка
            // Метод Прочитать() заново загрузит объект из базы данных
            // и автоматически обновит все вкладки, таблицы и реквизиты формы
            ФормаВладелец.Прочитать();
        Исключение
            // Обрабатываем исключение на случай, если форма заблокирована или закрыта
            ВызватьИсключение "Не удалось обновить форму документа: " + ОписаниеОшибки();
        КонецПопытки;
    КонецЕсли;
    
КонецПроцедуры

Способ 3. Оповещение формы через механизм Оповестить()

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

Рассмотрим реализацию этого сценария по шагам.

Шаг 1. В модуле формы внешней обработки после успешного изменения данных мы посылаем глобальное оповещение:


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

Шаг 2. В расширении для формы документа ВедомостьНаВыплатуЗарплатыВБанк переопределяем или добавляем обработчик события ОбработкаОповещения:


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

Способ 4. Использование штатных возможностей БСП «Заполнение объекта»

Если вы разрабатываете обработку в соответствии со стандартами БСП (Библиотека Стандартных Подсистем) для интеграции в справочник Дополнительные отчеты и обработки, вам не нужно изобретать велосипед.

При использовании типа команды ВызовКлиентскогоМетода или ВызовСерверногоМетода БСП предоставляет готовую инфраструктуру:

  1. В модуле внешней обработки в процедуре ВыполнитьКоманду вам передается параметр ОбъектыНазначения.
  2. Если команда выполняется на сервере, БСП автоматически передает измененные данные обратно на клиент.
  3. Платформа 1С самостоятельно применит метод КопироватьДанныеФормы к форме-владельцу, обновив все связанные динамические таблицы без написания дополнительного кода для обновления интерфейса.

Для этого важно правильно настроить метод СведенияОВнешнейОбработке, указав правильный тип запуска команды:


НоваяСтрока = ТаблицаКоманд.Добавить();
НоваяСтрока.Представление = "Заполнить ведомость (внешний пересчет)";
НоваяСтрока.Идентификатор = "ЗаполнитьВедомость";
НоваяСтрока.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
НоваяСтрока.ПоказыватьОповещение = Истина;

Способ 5. Метод ОбновитьОтображениеДанных()

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

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

ВладелецФормы.ОбновитьОтображениеДанных();

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

Используйте предложенные методы в зависимости от архитектуры вашего решения, и ваши внешние обработки будут работать корректно, быстро и бесшовно для конечных пользователей!

← На главную