Как обновить табличную часть документа из внешней обработки без нажатия кнопки «Перечитать»?

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

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

В чем заключается основная проблема?

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

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

Способ 1. Использование метода Прочитать() на форме

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


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

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

Важное предостережение: Метод Прочитать() полностью заменяет текущие данные формы данными из базы. Если пользователь до запуска вашей обработки внес в документ какие-то изменения (например, изменил комментарий или дату) и не нажал кнопку «Записать», то после вызова Прочитать() все его несохраненные правки будут безвозвратно утеряны. Проанализируйте этот риск перед внедрением данного метода.

Способ 2. Использование механизма БСП «Заполнение формы»

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

Разберем, как настроить такую команду в модуле внешней обработки. В функции СведенияОВнешнейОбработке необходимо указать соответствующий тип использования:


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

При использовании этого типа команды в процедуру ВыполнитьКоманду в модуле формы обработки передается специальный параметр ПараметрыВыполнения, в котором содержится ссылка на форму владельца. Посмотрим на пример реализации заполнения:


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

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

Способ 3. Взаимодействие через ВладелецФормы

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

В форме внешней обработки при нажатии кнопки «Заполнить» мы можем обратиться к контексту вызвавшей нас формы следующим образом:


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

Важно помнить, что в тонком клиенте прямое изменение ВладелецФормы.Объект работает только с коллекциями (табличными частями). Если вам нужно изменить простые реквизиты (например, склад или дату), лучше возвращать структуру данных обратно в форму документа и обрабатывать её там в процедуре ОбработкаВыбора или ОбработкаОповещения.

Оптимизация: Передача данных через временное хранилище

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

  1. На сервере внешней обработки формируем таблицу значений с результатами.
  2. Помещаем её во временное хранилище: Адрес = ПоместитьВоВременноеХранилище(ТЗ, ЭтаФорма.УникальныйИдентификатор);.
  3. Передаем Адрес на клиент.
  4. На клиенте в контексте формы документа вызываем серверный метод, который выполнит Объект.Товары.Загрузить(ПолучитьИзВременногоХранилища(Адрес));.

Метод Загрузить() работает значительно быстрее, чем добавление строк в цикле, так как минимизирует количество обращений к графической оболочке для отрисовки каждой новой строки.

Заключение

Мы рассмотрели различные подходы к обновлению данных табличной части. Выбор конкретного метода зависит от архитектуры вашей задачи:

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

← На главную