Почему процедура ОбработкаВыбора в 1С срабатывает только со второго раза?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В практике разработки на платформе 1С:Предприятие 8.3 (особенно в конфигурациях на управляемых формах, таких как УТ 11, ERP или КА) программисты часто сталкиваются с загадочным поведением интерфейса: при программном открытии формы выбора через событие НачалоВыбора, первый выбор элемента не дает результата, и только при повторном открытии окна данные корректно попадают в поле ввода. Рассмотрим детально, почему это происходит, и разберем способы решения этой задачи.

Анализ проблемы и поиск причин

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

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

Решение №1: Явный вызов обработчика через модальный режим

Хотя в современных версиях платформы использование модальности не рекомендуется (из-за ограничений веб-клиента), этот метод наглядно показывает логику взаимодействия. Проанализируем пример кода, который позволяет обойти проблему «второго раза» путем прямого управления возвратом значения:


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

В данном случае мы гарантируем, что программа дождется закрытия окна выбора и сразу передаст полученное значение в процедуру ТоварыНомерГТДОбработкаВыбора. Рассмотрим, как выглядит сама процедура обработки:


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

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

Чтобы избежать проблем с фокусом и не использовать устаревший метод ОткрытьМодально(), проанализируем более изящный способ. Вместо прямой модификации динамического списка формы через ПолучитьФорму(), правильнее передавать структуру отбора в параметрах метода ОткрытьФорму(). Это позволяет платформе самостоятельно связать окна и корректно отработать событие ОбработкаВыбора с первого клика.

Разберем алгоритм действий:

  1. Сформируем структуру отбора.
  2. Поместим её в структуру параметров открытия под ключом "Отбор".
  3. Укажем в качестве владельца Элемент (поле ввода), чтобы платформа знала, куда вернуть результат.

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

При таком подходе платформа 1С автоматически устанавливает РежимВыбора = Истина и связывает событие закрытия формы выбора с событием ОбработкаВыбора вашего поля. Проблема «второго раза» исчезает, так как контекст владельца передается в момент инициализации окна.

Влияние серверных вызовов и интерфейсных изменений

Посмотрим на ситуацию глубже. Иногда проблема кроется не в коде открытия, а в том, что происходит внутри процедур. Рассмотрим два критических фактора:

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

Проанализируем пример серверной функции записи:


&НаСервере
Функция ПроверитьНомерГТД(Номенклатура, Номер)
    // Получение объекта и запись — ресурсоемкая операция
    НоменклОбъект = Номенклатура.ПолучитьОбъект();
    // Логика проверки и добавления номера...
    НоменклОбъект.Записать(); 
КонецФункции

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

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

Заключение

Подведем итоги. Если ваша форма выбора срабатывает только со второго раза, проверьте следующие моменты:

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

← На главную