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