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

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

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

Анализ проблемы: почему данные не попадают в форму

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

  1. Неправильное определение владельца формы: Если обработка запущена как дополнительная, ВладелецФормы не всегда автоматически указывает на форму документа.
  2. Создание новой формы вместо использования текущей: Использование ОткрытьФорму с ключом ссылки создает новый контекст, если не указать уникальный идентификатор существующего окна.
  3. Особенности метода КопироватьДанныеФормы: Этот метод требует точного совпадения структур и понимания, какой объект является источником, а какой — приемником.

Способ 1: Использование метода КопироватьДанныеФормы и контекста владельца

Проанализируем программный код, который позволяет передать данные напрямую в открытую форму. Основная задача здесь — получить доступ к свойству Объект формы-владельца. Выясним, как это реализовать правильно.

Если мы работаем в контексте клиентского метода ВыполнитьКоманду, у нас есть доступ к параметру ОбъектыНазначения. Однако для обновления интерфейса нам нужна именно форма. Рассмотрим алгоритм:


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

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

В серверной процедуре ЗаполнитьТабличнуюЧастьНаСервере мы работаем с типом ДанныеФормыСтруктура. Это важно, так как прямое преобразование в ДокументОбъект через ДанныеФормыВЗначение потребует последующего обратного преобразования. Посмотрим на пример эффективного заполнения:


&НаСервере
Процедура ЗаполнитьТабличнуюЧастьНаСервере(ОбъектДанных)
    // Очищаем старые строки, если это необходимо
    ОбъектДанных.Корректировки.Очистить();
    
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ ..."; // Ваш запрос к данным
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        НоваяСтрока = ОбъектДанных.Корректировки.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
        // Дополнительная логика расчета
        НоваяСтрока.Сумма = Выборка.Сумма * -1;
    КонецЦикла;
КонецПроцедуры

Способ 2: Поиск открытого окна документа

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

Проанализируем ситуацию: пользователь открыл обработку, она что-то посчитала и должна «вбросить» данные в уже открытый документ. Рассмотрим, как это сделать:


&НаКлиенте
Процедура ПослеОтветаНаВопрос(Результат, ДополнительныеПараметры) Экспорт
    Если Результат <> КодВозвратаДиалога.Да Тогда
        Возврат;
    КонецЕсли;

    СсылкаНаДокумент = ДополнительныеПараметры.Ссылка;
    ОкнаПриложения = ПолучитьОкна();
    
    Для Каждого Окно Из ОкнаПриложения Цикл
        ФормаОкна = Окно.Содержимое;
        // Проверяем, что это форма нужного нам документа
        Если ТипЗнч(ФормаОкна) = Тип("УправляемаяФорма") 
            И Найти(ФормаОкна.ИмяФормы, "ФормаДокумента") > 0 Тогда
            
            Попытка
                Если ФормаОкна.Объект.Ссылка = СсылкаНаДокумент Тогда
                    // Мы нашли нужное окно!
                    ЗаполнитьОбъектНаСервере(ФормаОкна.Объект);
                    // Обновляем данные в найденной форме
                    КопироватьДанныеФормы(ФормаОкна.Объект, ФормаОкна.Объект); 
                    Возврат;
                КонецЕсли;
            Исключение
                Продолжить;
            КонецПопытки;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

Способ 3: Использование механизма оповещений (Оповестить)

Наиболее «чистым» с точки зрения архитектуры 1С методом является использование системы оповещений. Вместо того чтобы обработка «насильно» меняла данные в форме, она посылает сигнал: «Данные готовы, забирай».

Разберем по шагам, как это работает:

  1. В форме документа в процедуре ПриСозданииНаСервере или через свойства формы подписываемся на событие ОбработкаОповещения.
  2. В коде внешней обработки после завершения расчетов вызываем метод Оповестить("ЗаполнитьТЧИзОбработки", СтруктураДанных, СсылкаНаДокумент).
  3. В форме документа ловим это событие и обновляем таблицу.

Пример кода в обработке:


&НаКлиенте
Процедура ЗавершитьЗаполнение(ДанныеТЧ)
    ПараметрыОповещения = Новый Структура;
    ПараметрыОповещения.Вставить("Таблица", ДанныеТЧ);
    ПараметрыОповещения.Вставить("ДокументСсылка", Объект.ДокументСсылка);
    
    Оповестить("ЗаполнениеКорректировокЗавершено", ПараметрыОповещения);
КонецПроцедуры

Пример кода в форме документа:


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

Типичные ошибки при использовании КопироватьДанныеФормы

Рассмотрим ситуации, когда КопироватьДанныеФормы может не сработать или вызвать ошибку:

Выясним причину, по которой автор темы столкнулся с неудачей. В его коде используется конструкция: ВладелецФормы = ОткрытьФорму("...", Новый Структура("Ключ", Объект.Ссылка)); Это действие открывает вторую копию формы того же документа. Программа заполняет объект во второй (невидимой или новой) форме, в то время как пользователь смотрит в первую. Чтобы этого избежать, всегда проверяйте УникальныйИдентификатор формы и старайтесь передавать текущую форму в качестве владельца при открытии обработки заполнения.

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

← На главную