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

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

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

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

Постановка задачи и начальные шаги

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

Первым делом мы создаем элемент формы и связываем его с обработчиками событий. Рассмотрим, как это выглядит в коде:


// Пример добавления элемента на форму
НовыйЭлемент = Элементы.Добавить("ДоговорСОтбором", Тип("ПолеФормы"), ГруппаРодитель);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.ПутьКДанным = "Объект.Договор";

// Устанавливаем действие для события НачалоВыбора
НовыйЭлемент.УстановитьДействие("НачалоВыбора", "ОтборДоходныйДоговорНачалоВыбора");

Здесь важно отметить, что метод УстановитьДействие связывает событие элемента с процедурой, которая должна быть объявлена в модуле формы с директивой &НаКлиенте.

Проблема «двойного» открытия формы

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

Для решения этой проблемы крайне важно правильно объявить сигнатуру процедуры-обработчика. Она должна принимать параметры, среди которых есть СтандартнаяОбработка. Установка этого параметра в значение Ложь говорит системе, что мы берем управление процессом на себя.

Проанализируем правильную структуру обработчика:


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

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

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

Рассмотрим по шагам процесс создания таких настроек:

  1. Создаем объект НастройкиКомпоновкиДанных.
  2. Добавляем новый элемент отбора в коллекцию.
  3. Устанавливаем левое значение (поле, по которому фильтруем, в формате ПолеКомпоновкиДанных).
  4. Задаем вид сравнения (например, ВидСравненияКомпоновкиДанных.ВСписке).
  5. Устанавливаем правое значение (наш список значений или массив).
  6. Передаем эти настройки в параметры открытия формы под ключом ФиксированныеНастройки.

Выясним, как это реализовать в коде:


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

Нюансы возврата значения

Проанализируем важную деталь в вызове ОткрытьФорму. Третьим параметром мы передаем Элемент. В контексте обработчика НачалоВыбора это и есть то самое поле ввода, в которое пользователь должен поместить результат. Если не указать владельца, форма выбора откроется, пользователь нажмет на нужную строку, но в исходном поле ничего не изменится, так как форма «не знает», куда вернуть результат.

Если же логика требует дополнительной обработки выбранного значения (например, автоматического заполнения связанных полей на форме после выбора договора), мы рекомендуем использовать ОписаниеОповещенияОЗавершении.

Посмотрим на пример с использованием оповещения:


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

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

Альтернатива: Связи параметров выбора

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

Пример программной настройки связи:


// Описываем связь: поле "Владелец" в справочнике договоров 
// должно соответствовать значению "Объект.Контрагент" на форме
НоваяСвязь = Новый СвязьПараметраВыбора("Отбор.Владелец", "Объект.Контрагент");
МассивСвязей = Новый Массив;
МассивСвязей.Добавить(НоваяСвязь);

НовыйЭлемент.СвязиПараметровВыбора = Новый ФиксированныйМассив(МассивСвязей);

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

Заключение

Мы проанализировали основные способы реализации программного выбора с отбором. Подведем итог: для простых фильтров используйте СвязиПараметровВыбора или параметр Отбор структуры параметров формы. Для сложных условий (списки, вхождения, отрицания) наиболее гибким инструментом являются ФиксированныеНастройки компоновки данных. Главное — не забывайте отключать СтандартнаяОбработка и правильно указывать владельца или оповещение при открытии формы.

← На главную