Как обеспечить корректное отображение и обновление данных регистра сведений на обычных формах 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

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

Почему метод ОбновитьСтроки() оказывается бесполезным?

Разберем типичную ситуацию: у нас есть форма элемента справочника, на которой расположено табличное поле. Это поле связано с реквизитом типа РегистрСведенийНаборЗаписей. Мы программно добавляем запись в регистр, вызываем ЭлементыФормы.НашеТабличноеПоле.ОбновитьСтроки(), но список остается прежним. Проанализируем причину.

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

Решение 1: Работа с реквизитом типа РегистрСведенийНаборЗаписей

Если в качестве источника данных для табличного поля вы используете реквизит формы с типом РегистрСведенийНаборЗаписей, ключевым методом для вас станет Прочитать(). Рассмотрим по шагам, как правильно реализовать добавление записи и обновление интерфейса.

Предположим, наш реквизит называется Покупатели. Процедура обновления будет выглядеть следующим образом:


// Пример программного добавления записи и обновления формы
Процедура ДобавитьЗаписьНажать(Кнопка)
    
    // 1. Создаем объект для записи в базу
    НовыйНабор = РегистрыСведений.КонтрагентыПокупателей.СоздатьНаборЗаписей();
    НовыйНабор.Отбор.Контрагент.Установить(Ссылка);
    
    НоваяЗапись = НовыйНабор.Добавить();
    НоваяЗапись.Контрагент = Ссылка;
    НоваяЗапись.Период = ТекущаяДата();
    // Заполнение остальных полей...
    
    НовыйНабор.Записать(Ложь); // Записываем в базу данных
    
    // 2. Обновляем данные в реквизите формы
    // Важно: отбор у реквизита формы уже должен быть установлен (например, при открытии)
    ЭтотОбъект.Покупатели.Прочитать(); 
    
КонецПроцедуры

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

Решение 2: Отображение «Среза последних» через Таблицу Значений

Стандартный набор записей или список регистра на обычных формах не умеет отображать только актуальные значения (срез последних) без лишних манипуляций. Поэтому часто программисты используют ТаблицуЗначений в качестве источника данных. В этом случае автоматического обновления не произойдет вовсе — вам нужно вручную перезаполнить таблицу.

Выясним, как это реализовать эффективно. Создадим отдельную процедуру для обновления данных, которую будем вызывать из разных точек модуля:


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

Эту процедуру необходимо вызывать:

  1. В обработчике ПриОткрытии() основной формы.
  2. Сразу после кода, который вносит изменения в регистр сведений.
  3. В обработчике ПослеЗаписи(), если данные регистра зависят от состояния основного объекта.

Решение 3: Использование РегистрСведенийСписок

Если вам нужно отображать историю записей, проще всего использовать тип РегистрСведенийСписок. Он работает быстрее с большими объемами данных, так как использует динамическую выборку. Чтобы ограничить данные только текущим владельцем (контрагентом), используйте программную установку отбора.

Проанализируем пример настройки такого списка:


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

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

Механизм оповещений: Обновление из сторонних форм

Рассмотрим ситуацию, когда запись в регистр добавляется не в самой карточке контрагента, а в отдельной вспомогательной форме (например, форме записи регистра). Чтобы основная форма «узнала», что данные изменились, используем механизм оповещений.

Шаг 1: В форме, где происходит запись данных, вызываем оповещение:


Процедура ПослеЗаписи()
    Оповестить("ЗаписьРегистраПокупателиИзменена", СсылкаНаКонтрагента, ЭтотОбъект);
КонецПроцедуры

Шаг 2: В форме контрагента создаем обработчик ОбработкаОповещения:


Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    
    Если ИмяСобытия = "ЗаписьРегистраПокупателиИзменена" И Параметр = Ссылка Тогда
        // Вызываем один из методов обновления, описанных выше
        ОбновитьДанныеНаФорме(); 
    КонецЕсли;
    
КонецПроцедуры

Этот подход является наиболее профессиональным и «чистым», так как он исключает необходимость постоянно нажимать клавишу F5 или переоткрывать карточку для актуализации данных.

Итоги

Подведем итог нашему разбору. Выбор метода обновления зависит от того, как вы отображаете данные:

Помните, что визуальные методы типа ОбновитьСтроки() работают только с представлением данных, но не с самими данными. Всегда идите от обновления источника данных к его отображению, а не наоборот.

← На главную