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