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

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

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

Причина проблемы: Объект базы данных против Данных формы

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

Для корректного отображения данных нам нужно работать не с ДокументОбъект, а с Данными формы (ДанныеФормыСтруктура). Это специальный тип объектов, который "живет" на форме и изменения в котором мгновенно транслируются в интерфейс.

Способ 1. Использование ВладелецФормы (для типа «ВызовКлиентскогоМетода»)

Если ваша обработка зарегистрирована с типом команды ВызовКлиентскогоМетода, то при нажатии кнопки открывается форма самой обработки. В этом случае форма документа является "владельцем" для формы обработки. Рассмотрим, как правильно организовать заполнение в этом случае.

Шаг 1. На клиенте получаем доступ к объекту владельца. Мы не можем передать форму целиком на сервер, поэтому нам нужно работать с данными аккуратно.


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

Шаг 2. На сервере заполняем переданный объект. В современных версиях платформы 8.3 параметры типа ДанныеФормыСтруктура можно передавать на сервер и изменять их там.


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

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

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

Выясним, как это реализовать на практике:

  1. На сервере получаем структуру данных формы.
  2. Используем метод ДанныеФормыВЗначение для конвертации в ДокументОбъект.
  3. Выполняем все необходимые манипуляции (заполнение, расчеты).
  4. Используем метод ЗначениеВДанныеФормы, чтобы "вытолкнуть" изменения обратно в интерфейс.

Пример кода:


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

Способ 3. Использование типа команды «ЗаполнениеФормы»

Рассмотрим вариант, когда нам вообще не нужна форма внешней обработки. Библиотека стандартных подсистем (БСП) позволяет регистрировать обработки с видом ЗаполнениеОбъекта и использованием ЗаполнениеФормы. Это самый "чистый" способ с точки зрения архитектуры 1С.

В модуле объекта внешней обработки в процедуре ВыполнитьКоманду нам будет доступен параметр ПараметрыВыполнения.ЭтаФорма. Мы можем напрямую работать с ПараметрыВыполнения.ЭтаФорма.Объект. Преимущество здесь в том, что нам не нужно вручную прописывать ВладелецФормы, так как БСП сама передает контекст документа в обработку.

Пример регистрации такой команды в функции СведенияОВнешнейОбработке:


НоваяКоманда = ТаблицаКоманд.Добавить();
НоваяКоманда.Представление = "Заполнить по остаткам (БСП)";
НоваяКоманда.Идентификатор = "ЗаполнитьПоОстаткам";
НоваяКоманда.Использование = "ЗаполнениеФормы"; // Важно!
НоваяКоманда.ПоказыватьОповещение = Истина;

Важные нюансы при программном заполнении

Проанализируем несколько критических моментов, о которых часто забывают разработчики:

1. Модифицированность формы. После того как вы заполнили таблицу программно, форма документа может не "понять", что она изменилась. Если пользователь нажмет кнопку закрытия, программа может закрыть окно без вопроса о сохранении. Всегда устанавливайте ЭтаФорма.Модифицированность = Истина после завершения алгоритма заполнения.

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

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

4. Использование метода Загрузить(). Если у вас на сервере сформирована ТаблицаЗначений с колонками, имена которых совпадают с колонками табличной части документа, используйте метод Объект.ТЧ.Загрузить(ТЗ). Это работает значительно быстрее, чем добавление строк в цикле, так как выполняется одной низкоуровневой операцией.

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

← На главную