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

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

Мы часто сталкиваемся с ситуацией, когда после программного заполнения данных в табличной части управляемой формы на сервере, эти новые значения не сразу отображаются пользователю. Это особенно актуально для таких реквизитов, как "Серия" и "Упаковка", которые могут иметь специфическую логику отображения. Рассмотрим эту проблему на примере заполнения табличной части документа "Акт списания ЕГАИС" из данных "Реализации товаров и услуг" в конфигурации УТ 11.4. Наша задача — заставить форму обновиться и показать все значения, которые были программно установлены. Для комплексной автоматизации учета алкогольной продукции также настраивают обмен данными между 1С и ЕГАИС, обеспечивающий автоматическую сверку сведений об импортерах и производителях с государственным реестром.

Фундаментальные основы: Клиент-серверное взаимодействие и ДанныеФормы

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

Когда вы открываете форму документа или любого другого объекта, система создает две копии данных, которые живут в разных контекстах:

  1. Серверный объект (Объект): Это экземпляр самого объекта базы данных (например, ДокументОбъект.АктСписанияЕГАИС), который хранится в оперативной памяти сервера. Все изменения, которые вы делаете в коде на сервере, напрямую влияют на этот объект. Например, при добавлении новой строки в табличную часть Объект.Товары, вы модифицируете именно серверный объект.
  2. Данные формы (ЭтаФорма.ОсновнойРеквизит): Это специальная структура данных на клиенте, которая является представлением серверного объекта. Именно с этими данными взаимодействуют визуальные элементы формы (поля ввода, таблицы и т.д.). Когда вы изменяете что-то на форме через пользовательский интерфейс, эти изменения сначала попадают в данные формы, а затем, при необходимости (например, при нажатии кнопки "Записать"), синхронизируются с серверным объектом.

Ключевая проблема, с которой мы столкнулись: когда вы изменяете Объект на сервере (например, добавляете строки в табличную часть Объект.Товары), эти изменения автоматически не "проталкиваются" в ДанныеФормы на клиенте. Форма не "знает" о серверных изменениях, пока вы ей об этом явно не сообщите. Это приводит к тому, что хотя в серверном объекте данные уже есть, на клиентской форме они остаются невидимыми.

Анализ исходного кода и проблемных реквизитов

Давайте посмотрим на ваш код, который заполняет табличную часть документа "Акт списания ЕГАИС". Этот код выполняется на сервере, что подтверждается директивой &НаСервере:


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

Как видим, в этом коде мы напрямую манипулируем коллекцией Объект.Товары. Это абсолютно корректно для серверного контекста. Однако, после выполнения этой процедуры, изменения остаются на сервере. Клиентская форма, работающая с ДанныеФормы, не получает эти изменения автоматически. Именно поэтому реквизиты "Серия" и "Упаковка", которые вы заполняете, остаются невидимыми, пока вы не сделаете какое-либо действие, инициирующее обновление формы (например, запишете документ или перейдете по полям).

Решение проблемы: Передача данных и обновление отображения

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

  1. Передать изменения из серверного Объекта в ДанныеФормы на клиенте. Этот шаг синхронизирует логическую модель данных.
  2. Явно указать форме обновить ее визуальное представление. Этот шаг отвечает за перерисовку элементов интерфейса.

Шаг 1: Передача данных с сервера на клиент с помощью ЗначениеВДанныеФормы()

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

Синтаксис: ЗначениеВДанныеФормы(Источник, Приемник)

Где:

Добавим вызов этой функции в конец вашей серверной процедуры. Это нужно сделать после того, как все изменения в Объекте завершены:


&НаСервере
Процедура Портал_ОбработкаВыбораПослеНаСервере(ВыбранноеЗначение)
    // ... (ваш существующий код заполнения табличной части Объект.Товары) ...

    // После того, как мы заполнили табличную часть Объект.Товары на сервере,
    // необходимо передать все измененные данные основного объекта документа
    // в данные формы. Это критически важно, чтобы изменения, сделанные на сервере,
    // стали доступны для отображения на клиенте.
    ЗначениеВДанныеФормы(Объект, ЭтаФорма.ОсновнойРеквизит);

    // После выполнения этой строки, данные формы на клиенте будут актуальными,
    // но визуальное отображение элементов формы может еще не обновиться автоматически.
КонецПроцедуры

Теперь ДанныеФормы на клиенте содержат актуальные значения, включая "Серию" и "Упаковку". Следующим шагом будет их визуализация.

Шаг 2: Обновление отображения данных на клиенте с помощью ЭтаФорма.ОбновитьОтображениеДанных()

Несмотря на то, что данные формы обновлены (после ЗначениеВДанныеФормы()), клиентская часть интерфейса может не сразу перерисовать элементы, особенно если нет явного события, которое бы инициировало эту перерисовку. Для принудительного обновления визуального представления формы используется процедура ЭтаФорма.ОбновитьОтображениеДанных().

Внимание! Эта процедура должна быть вызвана на клиенте. Вы правильно отметили ошибку "Попытка применения процедуры как функции" в сообщении 6. Это происходит, когда вы пытаетесь использовать процедуру так, как будто она возвращает значение (например, Переменная = ЭтаФорма.ОбновитьОтображениеДанных()) или просто обращаетесь к ней как к свойству без скобок (ЭтаФорма.ОбновитьОтображениеДанных). Процедуры в 1С вызываются с круглыми скобками, даже если у них нет параметров.

Правильный вызов процедуры:

ЭтаФорма.ОбновитьОтображениеДанных();

Рассмотрим два типичных сценария, как это можно интегрировать в ваш код:

Сценарий 1: Серверная процедура вызывается из клиентского обработчика

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


// Процедура обработки нажатия кнопки на форме (выполняется на клиенте)
&НаКлиенте
Процедура Портал_КнопкаЗаполнитьНажать(Команда)
    // Предположим, что НекоеВыбранноеЗначение получается из какого-то элемента формы
    // или является результатом выбора пользователем.
    ПеременнаяСВыбраннымЗначением = Элементы.ПолеВыбораДокумента.Значение;

    // Вызываем серверную процедуру для заполнения табличной части.
    // Важно: Эта процедура вернет управление на клиент только после того, как Объект будет обновлен
    // и его данные будут переданы в ЭтаФорма.ОсновнойРеквизит с помощью ЗначениеВДанныеФормы().
    Портал_ОбработкаВыбораПослеНаСервере(ПеременнаяСВыбраннымЗначением); 

    // Теперь, когда данные формы актуальны и находятся на клиенте,
    // принудительно обновляем визуальное отображение элементов формы на клиенте.
    // Это заставит таблицу перерисоваться и показать новые значения, включая Серию и Упаковку.
    ЭтаФорма.ОбновитьОтображениеДанных();
КонецПроцедуры

// Серверная процедура, которую мы уже модифицировали в Шаге 1
&НаСервере
Процедура Портал_ОбработкаВыбораПослеНаСервере(ВыбранноеЗначение)
    // ... (ваш существующий код заполнения табличной части Объект.Товары) ...

    // Передаем измененные данные объекта в данные формы, чтобы они были доступны на клиенте.
    ЗначениеВДанныеФормы(Объект, ЭтаФорма.ОсновнойРеквизит);
КонецПроцедуры
Сценарий 2: Вызов клиентской процедуры из серверной (менее типичный, но возможный)

Если по какой-то причине вам нужно вызвать обновление формы непосредственно из серверной процедуры (например, если серверная процедура вызывается из фонового задания, из другой серверной процедуры, не имеющей прямого клиентского контекста, или из обработчика события, который выполняется только на сервере), то потребуется передать управление на клиент через клиентскую процедуру, которая затем выполнит обновление.


&НаСервере
Процедура Портал_ОбработкаВыбораПослеНаСервере(ВыбранноеЗначение)
    // ... (ваш существующий код заполнения табличной части Объект.Товары) ...

    // Передаем измененные данные объекта в данные формы.
    ЗначениеВДанныеФормы(Объект, ЭтаФорма.ОсновнойРеквизит);

    // Вызываем клиентскую процедуру для обновления формы.
    // Важно, что ОбновитьОтображениеНаКлиенте() должна быть
    // определена как &НаКлиенте, чтобы она могла работать с ЭтаФорма.
    ОбновитьОтображениеНаКлиенте(); 
КонецПроцедуры

// Эта процедура должна быть определена на клиенте
&НаКлиенте
Процедура ОбновитьОтображениеНаКлиенте()
    // Эта процедура просто вызывает обновление отображения формы на клиенте.
    ЭтаФорма.ОбновитьОтображениеДанных();
КонецПроцедуры

Дополнительные рекомендации и потенциальные нюансы

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

  1. Использование ОбновитьСтроки() для табличного поля:

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

    Пример:

    Элементы.Товары.ОбновитьСтроки();

    Где Товары – это имя элемента формы (табличного поля), привязанного к табличной части Объект.Товары. Обычно имя элемента формы совпадает с именем табличной части, но всегда лучше перепроверить это в палитре свойств элемента формы в конфигураторе.

  2. Идентификация элемента формы:

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

  3. Особенности реквизитов "Серия" и "Упаковка" в УТ 11.4:

    В конфигурациях, таких как Управление торговлей 11.4, поля "Серия" и "Упаковка" могут иметь дополнительную логику, связанную с механизмами учета номенклатуры по сериям и единицам измерения. Иногда их отображение может зависеть от других полей в той же строке (например, выбранной номенклатуры или характеристики). В вашем случае, если эти поля просто заполняются значением, то описанные выше методы ЗначениеВДанныеФормы() и ЭтаФорма.ОбновитьОтображениеДанных() должны сработать. Однако, если после обновления данных они все равно ведут себя некорректно (например, не отображаются поля ввода или выпадающие списки для выбора серии, хотя значение установлено), это может указывать на то, что необходимо дополнительно вызвать стандартные обработчики событий формы, которые обычно срабатывают при изменении номенклатуры или характеристики в строке табличной части. Но это уже более сложная и специфическая задача, которая, скорее всего, не требуется для простого прямого заполнения.

Применяя описанные шаги — сначала синхронизируя данные Объекта с ДаннымиФормы с помощью ЗначениеВДанныеФормы(), а затем обновляя визуальное представление формы на клиенте с помощью ЭтаФорма.ОбновитьОтображениеДанных() (или Элементы.ИмяВашейТабличнойЧасти.ОбновитьСтроки() для более точечного обновления) — вы сможете корректно отображать все программно заполненные значения в табличной части управляемой формы.

← На главную