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