В процессе разработки на платформе 1С:Предприятие 8.3 многие программисты переходят на использование асинхронных методов для работы с файловой системой. Это требование времени и современных стандартов веб-клиента. Однако часто возникает странная ситуация: при вызове метода ВыбратьАсинх или ПоказатьВыборФайла диалоговое окно открывается два раза подряд. Пользователь выбирает файл, нажимает «Открыть», и тут же видит то же самое окно снова.
В этой статье мы подробно разберем, почему «собака порылась» именно в логике кода, проанализируем типичные ошибки и составим алгоритм правильной реализации выбора файла.
Проанализируем ситуацию, когда вызов асинхронного метода помещен внутрь цикла или в процедуру, которая инициируется повторно. В асинхронной модели выполнение кода не останавливается на строке вызова диалога. Если в процедуре команды есть цикл, который не дожидается завершения выбора, система может успеть инициировать следующий вызов до того, как первое окно будет обработано.
Рассмотрим пример ошибочного кода, где выбор файла происходит внутри цикла обработки строк:
&НаКлиенте
Асинх Процедура КомандаЗагрузки(Команда)
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
// ОШИБКА: Диалог будет открываться для каждой строки!
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
ВыбранныйФайл = Ждать Диалог.ВыбратьАсинх();
Если ВыбранныйФайл <> Неопределено Тогда
ОбработатьФайл(ВыбранныйФайл[0]);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Выясним причину: даже если вы используете оператор Ждать, неправильная структура вызывающего кода (например, рекурсия или повторный вход в процедуру через обработчик ожидания) приведет к дублированию окон. Проверьте, не вызывается ли ваша процедура загрузки из событий, которые могут срабатывать дважды (например, изменение поля и окончание редактирования одновременно).
Разберем технический нюанс настройки формы. Часто разработчики назначают обработчик команды кнопке в конфигураторе, а затем, по привычке или из-за особенностей расширений, дублируют вызов в коде через УстановитьДействие или программное создание кнопок. В итоге одно нажатие на кнопку генерирует два события Нажатие, каждое из которых открывает свой диалог.
Что нужно проверить:
ПриСозданииНаСервере: нет ли там динамического назначения действий этой же кнопке.Если вы вызываете диалог выбора файла не по кнопке, а при нажатии на кнопку выбора в поле ввода (событие НачалоВыбора), критически важно отменить стандартное поведение платформы. Если этого не сделать, 1С сначала выполнит ваш программный код (откроет первое окно), а затем выполнит системное действие по умолчанию (откроет второе окно).
Посмотрим на пример правильной реализации в событии поля:
&НаКлиенте
Процедура ПутьКФайлуНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
// Обязательно устанавливаем Ложь, чтобы платформа не открывала свое окно
СтандартнаяОбработка = Ложь;
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Диалог.Показать(Новый ОписаниеОповещения("ЗавершитьВыборФайла", ЭтотОбъект));
КонецПроцедуры
Иногда пользователь делает быстрый двойной клик по кнопке. В обычном (модальном) режиме это не страшно, так как первое же окно блокирует интерфейс. В асинхронном режиме окно диалога появляется не мгновенно. Между кликом и появлением системного окна проходит несколько миллисекунд, которых достаточно, чтобы второй клик из очереди сообщений Windows инициировал повторный вызов процедуры.
Рассмотрим способ защиты с использованием «флага-предохранителя»:
&НаКлиенте
Перем ОкноВыбораОткрыто;
&НаКлиенте
Асинх Процедура ВыполнитьЗагрузкуАсинх(Команда)
// Проверяем, не запущен ли уже процесс выбора
Если ОкноВыбораОткрыто = Истина Тогда
Возврат;
КонецЕсли;
ОкноВыбораОткрыто = Истина;
Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
Попытка
ВыбранныеФайлы = Ждать Диалог.ВыбратьАсинх();
Если ВыбранныеФайлы <> Неопределено Тогда
// Логика обработки файла
КонецЕсли;
Исключение
// Обработка ошибок
КонецПопытки;
// Сбрасываем флаг
ОкноВыбораОткрыто = Ложь;
КонецПроцедуры
Проанализируем ситуацию, упомянутую в обсуждении: использование COMОбъект("Excel.Application"). Инициализация тяжелых объектов COM может занимать значительное время и влиять на очередь сообщений приложения. Если вы создаете объект Excel непосредственно перед вызовом диалога, это может вызвать задержки в обновлении интерфейса и привести к тому, что событие нажатия кнопки будет обработано повторно при «провисании» потока.
Рекомендация: Сначала получите путь к файлу через асинхронный диалог, и только после того, как управление вернется в код 1С и путь будет получен, инициируйте работу с COMОбъект. Не смешивайте интерфейсные задачи (выбор файла) и тяжелые вычислительные процессы (запуск Excel) в одной неразрывной цепочке действий.
Если диалог продолжает открываться дважды, выполните следующие шаги:
ВыбратьАсинх(). Когда диалог откроется второй раз, посмотрите в конфигураторе Отладка -> Стек вызовов. Это покажет, откуда пришел повторный вызов.Элементы.ИмяКнопки.Доступность = Ложь;, а в конце (включая блок Исключение) верните Истина. Это физически предотвратит повторное нажатие.НаСервере, убедитесь, что контекст формы не меняется таким образом, что это провоцирует повторную генерацию событий формы.Использование асинхронных методов требует более строгого отношения к структуре кода. Помните, что асинхронность — это не просто замена методов, это изменение логики взаимодействия пользователя и программы. Следуя приведенным выше советам, вы сможете избавиться от двойных окон и сделать работу с вашими обработками комфортной для пользователей.