Почему при двойном клике в форме выбора 1С событие срабатывает дважды и как это исправить?

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

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

Анализируем причину возникновения двойного события

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

  1. Выбор (Selection): Это низкоуровневое событие. Оно возникает всякий раз, когда пользователь делает двойной клик мышью по строке таблицы или нажимает клавишу Enter.
  2. ВыборЗначения (ValueChoice): Это событие более высокого уровня. Оно специфично именно для форм, работающих в режиме выбора (когда параметр РежимВыбора установлен в значение Истина).

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

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


&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    // Код срабатывает первым
    ОповеститьОВыборе(Элементы.Список.ТекущиеДанные.Ссылка);
КонецПроцедуры

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

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

Решение 1: Управление стандартной обработкой

Самый простой и правильный с точки зрения логики платформы способ — это прервать цепочку стандартных событий. Если мы решили обрабатывать выбор в событии Выбор, мы должны явно сообщить платформе, что стандартные действия выполнять не нужно. Разберем, как изменить код в форме выбора:


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

Установив СтандартнаяОбработка = Ложь, мы предотвращаем вызов события ВыборЗначения. Теперь при двойном клике или нажатии Enter данные будут переданы только один раз.

Решение 2: Использование единого обработчика

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

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


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

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

Решение 3: Проверка на дубли в обработке выбора

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


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

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

Нюансы открытия формы подбора

Разберем важный момент, касающийся параметров открытия формы. В исходном сообщении автор использует параметр ПараметрыФормы.Вставить("ЗакрыватьПриВыборе", Ложь). Именно этот режим превращает обычную форму выбора в форму "подбора".

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

Также проанализируем настройку ПараметрыФормы.Вставить("ВыбиратьДополнительные", Истина). Эта настройка позволяет выбирать группы справочника (если это разрешено в метаданных), что также может влиять на цепочку событий. Всегда проверяйте тип ВыбранноеЗначение в обработчике выбора, если ваш справочник имеет иерархическую структуру.

Итоги и рекомендации

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

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

← На главную