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