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

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

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

Рассмотрим подробно причины возникновения ошибки «Не найден экспортируемый метод» при создании объекта ОписаниеОповещения в общем модуле, проанализируем архитектурные ограничения платформы и изучим правильные способы реализации интерактивного ввода на основании.

Причина ошибки «Не найден экспортируемый метод» при вызове ОписаниеОповещения

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


// Некорректно (если вызов в общем модуле без указания контекста):
ОповещениеПриЗакрытии = Новый ОписаниеОповещения("ВыборЭлементаЗавершение", Параметры);

// Корректно:
ОповещениеПриЗакрытии = Новый ОписаниеОповещения("ВыборЭлементаЗавершение", ЭтотОбъект, Параметры);
// Или с явным указанием имени модуля:
ОповещениеПриЗакрытии = Новый ОписаниеОповещения("ВыборЭлементаЗавершение", РаботаСДокументамиКлиент, Параметры);

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


// Ошибка: перекрытие системного свойства ЭтотОбъект параметром процедуры
Процедура ЗаполнитьПоУсловию(ЭтотОбъект, Основание) Экспорт
    // Переменная ЭтотОбъект указывает на переданный документ, а не на текущий общий модуль!
    Оповещение = Новый ОписаниеОповещения("ВыборЗавершение", ЭтотОбъект, Параметры);
КонецПроцедуры

Для исправления этой проблемы необходимо либо переименовать параметр (например, на ДокументОбъект), либо явно указывать имя общего модуля вместо ЭтотОбъект.

Архитектурное ограничение: почему нельзя открыть форму из ОбработкаЗаполнения

Разберем ключевую причину, почему код открытия формы выбора не срабатывает при вводе на основании, даже если синтаксические ошибки исправлены.

Событие ОбработкаЗаполнения модуля объекта (и соответствующая подписка на событие) выполняются **строго на сервере**. На сервере физически отсутствуют методы работы с пользовательским интерфейсом, такие как ОткрытьФорму, а окно тонкого клиента не может приостановить выполнение серверного кода в ожидании ответа пользователя.

Стандартный механизм ввода на основании работает по следующей схеме:

  1. Пользователь нажимает кнопку «Ввести на основании».
  2. Платформа высылает серверный вызов: создается объект документа, вызывается ОбработкаЗаполнения на сервере.
  3. Сервер возвращает созданный объект на клиент.
  4. На клиенте открывается форма нового документа.

Вклиниться в середину серверного процесса ОбработкаЗаполнения с клиентским диалоговым окном технически невозможно. Разберем три правильных способа решения этой задачи.

Способ 1. Создание собственной клиентской команды ввода на основании (Рекомендуемый)

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

Шаг 1. На клиенте в обработчике команды открываем форму выбора с передачей оповещения:


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

КонецПроцедуры

Шаг 2. В процедуре обработки оповещения передаем выбранные данные в параметры открытия формы нового документа:


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

КонецПроцедуры

Шаг 3. В документе-приемнике в серверной процедуре ОбработкаЗаполнения принимаем структуру из ДанныеЗаполнения:


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

КонецПроцедуры

Способ 2. Запрос уточняющих данных при открытии формы созданного документа

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

  1. В процедуре ПриСозданииНаСервере формы создаваемого документа проверяем, что документ новый, и устанавливаем флаг необходимости выбора (например, во временную переменную формы ТребуетсяУточнениеData).
  2. В клиентском обработчике ПриОткрытии формы документа проверяем этот флаг. Если он равен Истина, вызываем ОткрытьФорму для формы выбора.
  3. После выбора значения пользователем в процедуре завершения вызываем серверную процедуру формы, которая дозаполняет реквизиты объекта. Если пользователь закрыл форму выбора без выбора — вызываем Закрыть() для формы нового документа.

Правильная установка отборов при открытии формы выбора

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


// Формирование структуры отбора для динамического списка формы выбора
СтруктураОтбора = Новый Структура("Ссылка", МассивРазрешенныхСсылок);
ПараметрыФормы = Новый Структура("Отбор", СтруктураОтбора);

ОткрытьФорму("Перечисление.Материалы.ФормаВыбора", ПараметрыФормы, Владелец, , , , Оповещение);

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

← На главную