Как заполнить таблицу на форме в процедуре «НаСервереБезКонтекста» и избежать ошибок

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

В процессе разработки на управляемых формах 1С часто возникает дилемма: использовать &НаСервере с передачей контекста всей формы или &НаСервереБезКонтекста для оптимизации. Основная проблема внеконтекстных вызовов заключается в том, что платформа запрещает напрямую изменять реквизиты формы, так как они просто не передаются на сервер. При попытке передать таблицу формы как параметр и изменить её, разработчик получает ошибку: «Нельзя изменять поле, содержащее объект данных формы». Рассмотрим подробно, как решить эту задачу, минимизировать трафик и правильно организовать передачу данных.

Почему возникает ошибка и как работает контекст

Разберем ситуацию: когда мы вызываем процедуру &НаСервере, платформа автоматически сериализует всю форму (все её реквизиты, включая невидимые таблицы, деревья и данные объектов) и отправляет на сервер. После выполнения кода форма так же целиком возвращается обратно. Если форма «тяжелая», это создает огромную нагрузку на сеть.

Процедура &НаСервереБезКонтекста не получает данных формы. Если мы передаем в неё ДанныеФормыКоллекция (нашу таблицу) напрямую, платформа пытается передать лишь ссылку на объект, который на сервере без контекста не существует. Именно поэтому возникает ошибка доступа к объекту. Однако существуют обходные пути, позволяющие достичь цели.

Способ 1: Использование ключевого слова Знач (ByVal)

Проанализируем самый простой, но требующий понимания способ. Если в заголовке серверной процедуры указать ключевое слово Знач для параметра таблицы, платформа выполнит полную сериализацию этого объекта. Это позволит «протащить» данные на сервер без контекста всей остальной формы.

Рассмотрим пример реализации:


&НаКлиенте
Процедура ОбновитьЦветаНаКлиенте()
    // Передаем таблицу формы в процедуру без контекста
    ОбновитьТаблицуНаСервере(ТЗ_ЦветаИКнопки);
КонецПроцедуры

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

Важный нюанс: использование Знач заставляет платформу передавать всю таблицу целиком. Если в таблице 10 000 строк, внеконтекстный вызов может стать медленнее контекстного, так как контекстный вызов передает только измененные данные («дифференциально»), а Знач — всегда полную копию.

Способ 2: Преобразование в массив структур (Рекомендуемый)

Выясним причину, по которой этот метод считается наиболее «чистым» с точки зрения архитектуры 1С. Вместо передачи сложных объектов ДанныеФормыКоллекция, мы преобразуем таблицу в массив структур. Массив структур — это универсальный сериализуемый тип, который легко передается между клиентом и сервером.

Рассмотрим пошаговый алгоритм:

  1. На клиенте формируем массив структур на основе данных таблицы.
  2. Передаем массив в функцию &НаСервереБезКонтекста.
  3. На сервере обрабатываем данные и возвращаем новый массив.
  4. На клиенте очищаем таблицу формы и заполняем её данными из возвращенного массива.

Пример кода:


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

&НаСервереБезКонтекста
Функция ОбработатьДанныеНаСервере(Номенклатура, Данные)
    // Здесь работаем с массивом структур
    // Можно преобразовать в ТЗ для удобства (через создание колонок)
    // Возвращаем обработанный массив
    Возврат Данные; 
КонецФункции

Способ 3: Использование метода КопироватьДанныеФормы

Существует «хак», который позволяет избежать ручного перебора строк на клиенте. Мы можем использовать метод КопироватьДанныеФормы. Посмотрим на пример ситуации, когда это удобно:


&НаКлиенте
Процедура ЗаполнитьЧерезКопирование()
    // Создаем временную переменную, которая не является реквизитом формы напрямую
    ВременнаяТЗ = ТЗ_ЦветаИКнопки; 
    
    // Передаем её на сервер (используя Знач в приемнике)
    ЗаполнитьДанныеНаСервере(ВременнаяТЗ);
    
    // Синхронизируем изменения обратно в реквизит формы
    КопироватьДанныеФормы(ВременнаяТЗ, ТЗ_ЦветаИКнопки);
КонецПроцедуры

Этот метод работает, потому что при присваивании ВременнаяТЗ = ТЗ_ЦветаИКнопки на клиенте создается локальная копия указателя, которую платформа позволяет передать более гибко. Однако помните, что метод КопироватьДанныеФормы на клиенте имеет ограничения по типам данных.

Способ 4: Временное хранилище (для больших объемов)

Если таблица содержит десятки тысяч строк, передавать её параметром (даже через Знач) — плохая практика. Проанализируем решение через ПоместитьВоВременноеХранилище.

Алгоритм действий:

  1. На сервере (в контекстном вызове при открытии или по кнопке) данные помещаются в хранилище.
  2. На клиента возвращается только Адрес (строка).
  3. В процедуру &НаСервереБезКонтекста передается этот адрес.
  4. На сервере данные извлекаются по адресу через ПолучитьИзВременногоХранилища, обрабатываются и кладутся обратно.
  5. На клиенте вызывается обновление формы из хранилища.

Проблема динамических подсказок и элементов управления

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

Рассмотрим альтернативы:

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

← На главную