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