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