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