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

Программист IT и автоматизация бизнеса
← На главную

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

Разберем причину возникновения проблемы

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

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

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


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

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

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

Способ 2. Обновление через ЗначениеВРеквизитФормы

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

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

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

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

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

Способ 3. Оповещение об изменении (для связанных форм)

Бывают ситуации, когда документ изменяется не в своей собственной форме, а в какой-то внешней обработке или из формы списка. В этом случае открытая форма документа должна узнать, что данные «под ней» изменились. Для этого в 1С существует механизм оповещений. Рассмотрим его применение.

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

Оптимизация работы с табличными частями

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

Вместо перебора строк в цикле, мы можем подготовить Таблицу Значений (ТЗ) с нужными данными и загрузить её целиком. Посмотрим на пример:


// На сервере
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Месяцы");
ТаблицаДанных.Колонки.Добавить("ДниНедели");

// Заполняем ТЗ...
НоваяЗапись = ТаблицаДанных.Добавить();
НоваяЗапись.Месяцы = "Январь";

// Загружаем одним махом в ТЧ документа
НашОбъект.ТЧ.Загрузить(ТаблицаДанных);

Метод Загрузить() автоматически сопоставляет имена колонок ТЗ и ТЧ, очищает старые записи и вставляет новые максимально быстро. Это «хороший тон» разработки в 1С.

Подведем итоги

Для успешного обновления табличной части в форме документа выберите подходящую стратегию:

  1. Если данные уже записаны в базе — используйте ЭтаФорма.Прочитать() на клиенте.
  2. Если вы хотите обновить экран без немедленной записи в базу — используйте пару РеквизитФормыВЗначение и ЗначениеВРеквизитФормы на сервере.
  3. Если необходимо визуально обновить только оформление или связанные итоги без перезагрузки данных — используйте ЭтаФорма.ОбновитьОтображениеДанных().

Помните о конфликте версий: если программная запись происходит в одном сеансе, а форма открыта в другом, пользователь при попытке записи получит сообщение «Данные были изменены или удалены другим пользователем». В таких сценариях использование ЭтаФорма.Прочитать() перед началом работы пользователя является обязательным условием стабильной работы системы.

← На главную