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

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

В разработке на платформе 1С:Предприятие 8 часто возникает задача открыть форму списка (например, регистра сведений, справочника или документа) с предустановленным фильтром по определенному реквизиту. Казалось бы, задача тривиальная, однако начинающие разработчики часто сталкиваются с неочевидными ошибками. Самая распространенная среди них — ошибка передачи данных XDTO и сообщение вида «Отсутствует отображение для типа ПолеФормы».

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

Выясняем причину ошибки: Элементы формы vs Данные формы

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


Пр = Элементы.ПредметЛизинга;  
П = Новый Структура("Пр", Пр);
Форма = ПолучитьФорму("РегистрСведений.ИсторияМенеджеров.ФормаСписка", П);
Форма.Открыть();

При выполнении этого фрагмента платформа сгенерирует критическую ошибку: «Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа... Ошибка отображения типов: Отсутствует отображение для типа 'ПолеФормы'».

Почему это происходит? Переменная Пр в данном случае получает значение из коллекции Элементы. Коллекция Элементы содержит объекты визуального интерфейса — элементы управления (кнопки, поля ввода, таблицы). В данном примере тип переменной — ПолеФормы. Элементы формы созданы исключительно для отображения на клиенте. Их невозможно передать на сервер или использовать в параметрах открытия формы, так как они не могут быть сериализованы (превращены в XML/JSON для передачи по сети).

Важное правило: Нам нужны не элементы управления, а сами данные, которые в них находятся. Данные хранятся в реквизитах формы. Найти связь между визуальным элементом и данными очень просто — достаточно посмотреть свойство элемента ПутьКДанным в конфигураторе. Например, если поле связано с реквизитом объекта, то путь к данным будет выглядеть как Объект.ПредметЛизинга.

Правильный базовый вариант установки отбора

Для того чтобы открыть форму списка с фильтром, в платформе 1С предусмотрен стандартный механизм. Мы должны передать в открываемую форму параметр с предопределенным именем "Отбор". Значением этого параметра должна быть структура, где:

Давайте перепишем наш код правильно. Вместо метода ПолучитьФорму() мы будем использовать более современный и быстрый метод управляемого интерфейса ОткрытьФорму().


// 1. Извлекаем данные из реквизита формы (а не из элемента управления)
ЗначениеОтбора = Объект.ПредметЛизинга; 

// 2. Создаем структуру отбора. Ключ должен строго совпадать с именем поля в регистре
СтруктураОтбора = Новый Структура("ПредметЛизинга", ЗначениеОтбора);

// 3. Помещаем структуру отбора в параметры запуска формы под стандартным ключом "Отбор"
ПараметрыФормы = Новый Структура("Отбор", СтруктураОтбора);

// 4. Открываем форму списка регистра сведений с наложенным фильтром
ОткрытьФорму("РегистрСведений.ИсторияМенеджеров.ФормаСписка", ПараметрыФормы);

Этот лаконичный код решает проблему целиком: данные успешно передаются, фильтрация отрабатывает на стороне платформы автоматически, а интерфейс не выдает никаких ошибок.

Важный нюанс: Проблема повторного открытия и уникальность формы

Представим ситуацию: пользователь нажал кнопку, открылась форма списка с отбором по «Предмету лизинга А». Не закрывая это окно, пользователь возвращается в документ, выбирает «Предмет лизинга Б» и снова нажимает кнопку. Что произойдет?

По умолчанию 1С попытается найти уже открытую форму этого регистра. Она найдет старое окно с «Предметом лизинга А» и просто активизирует его (выведет на передний план). Новый отбор при этом не применится! Чтобы решить эту проблему, мы должны управлять уникальностью формы при ее открытии. Для этого используется четвертый параметр метода ОткрытьФорму.

У нас есть два пути решения:

  1. Всегда открывать новое окно: Для этого в качестве ключа уникальности нужно передать значение Истина. При каждом нажатии будет плодиться новое окно списка.
    
    ОткрытьФорму("РегистрСведений.ИсторияМенеджеров.ФормаСписка", ПараметрыФормы, , Истина);
    
  2. Использовать ключ уникальности на основе объекта: Если мы хотим, чтобы для каждого конкретного предмета лизинга открывалось строго одно уникальное окно (но при этом окон для разных предметов лизинга могло быть несколько), мы передаем ссылку на сам объект в качестве ключа уникальности:
    
    КлючУникальности = Объект.ПредметЛизинга;
    ОткрытьФорму("РегистрСведений.ИсторияМенеджеров.ФормаСписка", ПараметрыФормы, , КлючУникальности);
    

Реализация сложных отборов через "ФиксированныеНастройки"

Передача структуры в параметр "Отбор" работает исключительно по условию равенства (вид сравнения «Равно»). Но что делать, если перед нами стоит задача сделать отбор по нескольким элементам списка (вид сравнения «В списке»), исключить значение («Не равно») или отобрать документы за период?

В таких случаях стандартная структура параметров не справится. Нам потребуется использовать другой зарезервированный параметр формы — "ФиксированныеНастройки". Сюда мы передаем объект типа НастройкиКомпоновкиДанных. Давайте разберем по шагам, как программно заполнить такой отбор:


// Создаем объект настроек компоновки данных
Настройки = Новый НастройкиКомпоновкиДанных;

// Добавляем новый элемент отбора в коллекцию
ЭлементОтбора = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));

// Указываем поле, по которому будем фильтровать. Поле задается специальным типом
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ПредметЛизинга");

// Задаем вид сравнения. Например, выберем поиск в списке значений
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;

// Заполняем правое значение. Это может быть массив или список значений
СписокПредметов = Новый СписокЗначений;
СписокПредметов.Добавить(Объект.ПредметЛизинга);
СписокПредметов.Добавить(ДругойПредметЛизинга);
ЭлементОтбора.ПравоеЗначение = СписокПредметов;

// Активируем использование этого отбора
ЭлементОтбора.Использование = Истина;

// Помещаем сформированные настройки в параметры открытия формы
ПараметрыФормы = Новый Структура("ФиксированныеНастройки", Настройки);

// Открываем форму списка
ОткрытьФорму("РегистрСведений.ИсторияМенеджеров.ФормаСписка", ПараметрыФормы);

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

Альтернативный вариант: Ручная обработка параметров на стороне принимающей формы

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

Разберем этот сценарий.

Шаг 1. Передача произвольного параметра при открытии:


// Формируем структуру с любым удобным нам именем ключа
ПараметрыФормы = Новый Структура("МойПараметрПредметЛизинга", Объект.ПредметЛизинга);

// Открываем форму списка
ОткрытьФорму("РегистрСведений.ИсторияМенеджеров.ФормаСписка", ПараметрыФормы);

Шаг 2. Прием и обработка параметра в открываемой форме:

В модуле формы списка регистра (в нашем примере это форма списка регистра ИсторияМенеджеров) переходим в обработчик события ПриСозданииНаСервере и пишем код ручной установки отбора в динамическом списке с именем Список:


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

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

← На главную