В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда необходимо программно изменить данные документа (например, заполнить табличную часть из другой формы или обработки), но открытая форма этого документа не отображает внесенные изменения. Проблема заключается в том, что объект в памяти (ДокументОбъект) и данные, отображаемые на экране (ДанныеФормы), — это разные сущности. Рассмотрим подробнее, как правильно синхронизировать эти данные и заставить интерфейс обновиться.
Когда мы получаем объект через метод ПолучитьОбъект(), мы работаем с данными напрямую в базе данных или в оперативной памяти сервера. В то же время у пользователя может быть открыта форма этого документа. Форма хранит свою копию данных в специальном хранилище Объект (тип ДанныеФормыСтруктура). Если мы программно изменили и записали объект в базе данных, форма «не знает» об этом изменении и продолжает показывать старую версию данных, которая была актуальна на момент открытия окна. Проанализируем основные способы решения этой задачи.
Это самый простой и надежный способ в случаях, когда изменения уже были записаны в базу данных. Метод ЭтаФорма.Прочитать() заставляет платформу перечитать данные из базы и полностью обновить содержимое реквизита Объект в форме. Посмотрим на практический пример кода, который был предложен в обсуждении:
&НаСервереБезКонтекста
Процедура ЗаполнитьТЧНаСервере(Ссылка)
// Получаем объект из базы данных
НашОбъект = Ссылка.ПолучитьОбъект();
// Очищаем и заполняем табличную часть заново
НашОбъект.ТЧ.Очистить();
Для Счетчик = 1 По 12 Цикл
НоваяСтрока = НашОбъект.ТЧ.Добавить();
// Здесь логика заполнения реквизитов строки
КонецЦикла;
// Обязательно записываем объект, иначе Прочитать() не увидит изменений
НашОбъект.Записать();
КонецПроцедуры
&НаКлиенте
Процедура КомандаЗаполнить(Команда)
// Вызываем серверную процедуру для модификации данных в БД
ЗаполнитьТЧНаСервере(Объект.Ссылка);
// Обновляем данные в текущей открытой форме
ЭтаФорма.Прочитать();
КонецПроцедуры
Важно помнить: метод Прочитать() полностью сбрасывает все незаписанные изменения, которые пользователь мог внести в форму вручную до нажатия кнопки заполнения. Если пользователь что-то редактировал и не нажал «Записать», его правки будут потеряны.
Если нам нужно обновить данные в форме, но мы не хотим принудительно записывать документ в базу данных (давая пользователю возможность самому решить, сохранять изменения или нет), следует использовать методы преобразования данных формы в объект и обратно. Рассмотрим, как это работает.
В управляемом приложении мы можем сконвертировать ДанныеФормы в полноценный ДокументОбъект, выполнить с ним любые действия (заполнить ТЧ, проверить условия) и вернуть результат обратно в форму. Проанализируем последовательность действий:
Объект.РеквизитФормыВЗначение("Объект") для получения объекта.ЗначениеВРеквизитФормы(ДокументОбъект, "Объект") для возврата данных в интерфейс.
&НаСервере
Процедура ОбновитьБезЗаписиНаСервере()
// Преобразуем данные формы в объект документа
ДокОбъект = РеквизитФормыВЗначение("Объект");
// Выполняем программное заполнение
ДокОбъект.ТЧ.Очистить();
НоваяСтрока = ДокОбъект.ТЧ.Добавить();
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию("Услуга");
// Возвращаем измененный объект в реквизиты формы
ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
// Устанавливаем признак модифицированности, чтобы форма предложила записаться при закрытии
ЭтаФорма.Модифицированность = Истина;
КонецПроцедуры
Преимущество этого метода в том, что он работает быстрее (нет лишнего обращения к СУБД для записи) и корректно обрабатывает транзакционную логику: данные на экране обновились, но документ в базе остался прежним до явного действия пользователя.
Бывают ситуации, когда документ изменяется не в своей собственной форме, а в какой-то внешней обработке или из формы списка. В этом случае открытая форма документа должна узнать, что данные «под ней» изменились. Для этого в 1С существует механизм оповещений. Рассмотрим его применение.
После программной записи объекта в коде обработки рекомендуется вызвать метод ОповеститьОбИзменении(Ссылка). Это глобальный сигнал системе, который заставляет обновиться все динамические списки, где отображается данный объект. Если же нужно обновить именно форму объекта, в ней можно прописать обработчик ОбработкаОповещения, который будет реагировать на изменения и вызывать ЭтаФорма.Прочитать().
Выясним, как сделать процесс заполнения табличной части более производительным. В первом сообщении темы автор добавляет строки в цикле. Если строк сотни или тысячи, это может замедлить работу интерфейса. Рекомендуется использовать метод Загрузить().
Вместо перебора строк в цикле, мы можем подготовить Таблицу Значений (ТЗ) с нужными данными и загрузить её целиком. Посмотрим на пример:
// На сервере
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Месяцы");
ТаблицаДанных.Колонки.Добавить("ДниНедели");
// Заполняем ТЗ...
НоваяЗапись = ТаблицаДанных.Добавить();
НоваяЗапись.Месяцы = "Январь";
// Загружаем одним махом в ТЧ документа
НашОбъект.ТЧ.Загрузить(ТаблицаДанных);
Метод Загрузить() автоматически сопоставляет имена колонок ТЗ и ТЧ, очищает старые записи и вставляет новые максимально быстро. Это «хороший тон» разработки в 1С.
Для успешного обновления табличной части в форме документа выберите подходящую стратегию:
ЭтаФорма.Прочитать() на клиенте.РеквизитФормыВЗначение и ЗначениеВРеквизитФормы на сервере.ЭтаФорма.ОбновитьОтображениеДанных().Помните о конфликте версий: если программная запись происходит в одном сеансе, а форма открыта в другом, пользователь при попытке записи получит сообщение «Данные были изменены или удалены другим пользователем». В таких сценариях использование ЭтаФорма.Прочитать() перед началом работы пользователя является обязательным условием стабильной работы системы.