Как программно открыть форму выбора с отбором в 1С 8.3 и почему не работает ОбработкаВыбора

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

В процессе разработки на управляемых формах в «1С:Предприятие 8.3» часто возникает задача: ограничить список выбора в одном поле ввода на основании значения, указанного в другом поле. Например, если в обработке или документе заполнен реквизит «Проект», то при выборе связанного документа система должна показывать только те документы, которые относятся к выбранному проекту. Если же проектов выбрано несколько (или используется список значений), отбор должен осуществляться по всем этим проектам одновременно (вид сравнения «В списке»).

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

Почему не работает стандартный возврат значения в форму? Разбор ошибки

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


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

В приведенном коде содержатся сразу две серьезные ошибки, из-за которых логика ломается:

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

Рассмотрим подробнее все варианты правильного решения данной задачи.

Решение №1: Передача владельца формы (исправление основной ошибки)

Самое быстрое исправление программного кода заключается в передаче элемента формы в качестве третьего параметра метода ОткрытьФорму. Параметр Элемент передается в сам обработчик события НачалоВыбора платформой автоматически.

Посмотрим на исправленный и рабочий вариант кода:


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

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

Решение №2: Использование фиксированных настроек компоновки данных

Стандартный параметр Отбор, передаваемый при открытии формы, имеет один недостаток: пользователь может зайти в настройки списка в открывшемся окне выбора и самостоятельно отключить или изменить этот отбор. Если бизнес-логика требует жесткого ограничения выбора без возможности изменения условий пользователем, рекомендуется использовать ФиксированныеНастройки компоновки данных динамического списка.

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


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

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

Решение №3: Настройка связи параметров выбора в конфигураторе (без кода)

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

Выполним следующие шаги в конфигураторе:

  1. Откроем форму, на которой расположены наши реквизиты.
  2. Выделим элемент формы, предназначенный для ввода документа (поле ввода).
  3. В панели свойств найдем свойство Связи параметров выбора (Choice parameter links).
  4. Нажмем кнопку открытия и добавим новую строку связи.
  5. В поле Имя параметра выбора укажем Отбор.НомерПроектаДоговора.
  6. В поле Путь к данным выберем реквизит текущей формы (например, Объект.Проект).

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

Решение №4: Асинхронная обработка выбора через ОписаниеОповещения

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

Рассмотрим, как это реализовать:


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

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

Использование ОписаниеОповещения гарантирует корректную работу интерфейса и соответствует современным стандартам разработки фирмы «1С» для асинхронных вызовов в управляемом приложении.

← На главную