Почему не обновляется значение реквизита табличной части на клиенте в 1С 8.3 и как это исправить?

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

При разработке и кастомизации управляемых форм в «1С:Предприятии 8.3» программисты часто сталкиваются с загадочным поведением интерфейса: данные в табличной части программно изменяются, отладчик послушно показывает новые значения в объекте, но на экране пользователя колонка остается пустой или сохраняет старые данные. Ситуация усложняется тем, что стандартные методы обновления отображения формы не приносят желаемого результата, а данные на форме обновляются только после физической записи документа в базу данных.

В этой статье мы подробно разберем, почему возникает этот «эффект полтергейста» на управляемых формах (особенно в крупных типовых конфигурациях вроде ERP, Комплексной автоматизации или Управления торговлей), проанализируем внутренние механизмы платформы и предложим несколько надежных способов решения проблемы.

Выясняем причину: почему отладчик видит данные, а форма — нет?

Для начала проанализируем типичный сценарий, который приводит к подобной ошибке. Допустим, мы выполняем очистку и последующее заполнение табличной части на клиенте следующим образом:


&НаКлиенте
Процедура ВыполнитьПослеОтветаНаВопросОчисткаТЧ()
    // Очищаем коллекцию на клиенте
    Объект.Товары.Очистить();
    
    // Получаем массив новых строк с сервера
    МассивСтрокТЧ = ПолучитьСтрокиТЧПоЗаказу(ДополнительныеПараметры, Объект.Дата);
    
    // Заполняем табличную часть новыми строками
    Для каждого ЭлМассива Из МассивСтрокТЧ Цикл
        НоваяСтрокаТЧ = Объект.Товары.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрокаТЧ, ЭлМассива);
    КонецЦикла;
КонецПроцедуры

После этого мы пытаемся в цикле изменить значение какого-либо реквизита в строках (например, установить новое назначение для товаров):


&НаКлиенте
Процедура ВыполнитьПослеВыбораНовогоНазначения()
    Для каждого СтрокаТЧ Из Объект.Товары Цикл
        СтрокаТЧ.НовоеНазначение = РезультатЗакрытия;
    КонецЦикла;
КонецПроцедуры

На первый взгляд, код абсолютно корректен. Однако на практике после выполнения этой цепочки действий колонка «Новое назначение» на форме останется пустой. При этом в отладчике в коллекции Объект.Товары все значения будут заполнены правильно. Почему так происходит?

Рассмотрим главные причины рассинхронизации данных и интерфейса:

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

Рассмотрим подробнее эффективные практические способы решения этой проблемы.

Способ 1. Вызов оригинальных процедур постобработки и пересчета данных

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

Для восстановления корректного отображения нам необходимо принудительно вызвать обработчики событий после программного изменения данных. Посмотрим, как модифицировать код:


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

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

Способ 2. Принудительное оповещение платформы об изменении данных формы

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

Для этого в платформе «1С:Предприятие 8.3» предусмотрен специальный метод ОтобразитьИзменениеДанных(). Изменим наш код с его использованием:


&НаКлиенте
Процедура ВыполнитьПослеВыбораНовогоНазначения()
    Для каждого СтрокаТЧ Из Объект.Товары Цикл
        СтрокаТЧ.НовоеНазначение = РезультатЗакрытия;
    КонецЦикла;
    
    // Явно указываем платформе, что коллекция данных была изменена.
    // Это гарантированно обновит экранные элементы и визуализирует новые значения.
    ОтобразитьИзменениеДанных(Объект.Товары, ВидИзмененияДанных.Изменение);
КонецПроцедуры

Также в ряде случаев для обновления связанных ссылочных полей помогает вызов метода оповещения:

ОповеститьОбИзменении(Объект.Ссылка);

Способ 3. Перенос заполнения табличной части на сервер (Best Practice)

Многократное добавление строк в ДанныеФормыКоллекция на клиенте в цикле — крайне нерекомендуемый подход с точки зрения производительности и стабильности интерфейса. Правильным и наиболее надежным решением является перенос всей логики очистки и заполнения таблицы на сторону сервера.

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

Проанализируем пример реализации такого подхода:


&НаКлиенте
Процедура ВыполнитьПослеОтветаНаВопросОчисткаТЧ()
    // Вместо очистки и заполнения на клиенте, вызываем серверную процедуру
    ЗаполнитьТабличнуюЧастьНаСервере();
КонецПроцедуры

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

Использование метода ЗначениеВРеквизитФормы() гарантирует, что все связанные элементы управления формы, условное оформление и платформенные кэши будут пересчитаны автоматически и без ошибок.

Резюме

Если у вас не обновляются данные в табличной части на клиенте, выполните следующие шаги для локализации и устранения проблемы:

← На главную