Разработка удобного и отзывчивого интерфейса в управляемом приложении 1С:Предприятие 8.3 часто наталкивается на аппаратные ограничения платформы. Одной из таких «болевых точек» является стандартный платформенный поиск в динамических списках. Разработчики часто сталкиваются с ситуацией, когда пользователю приходится совершать лишние действия (например, нажимать клавишу Enter для перехода к результатам поиска) или когда стандартный поиск невозможно очистить программно после выбора элемента.
В этой статье мы подробно разберем, почему стандартный поиск ведет себя именно так, как обойти ограничение с фокусом ввода с помощью кастомного поиска, и рассмотрим рабочие сценарии программной очистки отборов динамического списка.
Давайте проанализируем штатное поведение платформы. Когда пользователь открывает форму со списком (например, справочник товаров) и начинает вводить символы прямо с клавиатуры, платформа автоматически активирует системный элемент «Строка поиска». При этом происходят следующие процессы:
Попытки программно перехватить ввод каждого символа в системную строку поиска или принудительно активировать таблицу списка в процессе ввода не увенчаются успехом. В управляемом интерфейсе 1С отсутствуют события, позволяющие отслеживать посимвольный ввод в стандартное поле поиска «на лету». Платформа жестко контролирует этот элемент, и управлять им из встроенного языка невозможно.
Если перед нами стоит задача сделать поиск бесшовным — чтобы отбор происходил мгновенно, а пользователь мог сразу перемещаться по списку без лишних нажатий клавиш — нам придется отказаться от стандартного платформенного механизма и реализовать собственный «умный» поиск.
Если мы просто создадим текстовое поле на форме и привяжем наложение отбора к событию ИзменениеТекстаРедактирования, то столкнемся с проблемой «фриза» интерфейса. При вводе каждого символа форма будет выполнять серверный вызов для фильтрации списка, фокус будет «улетать» из поля ввода, и пользователь не сможет комфортно набрать даже короткое слово.
Чтобы решить эту проблему, применим классический паттерн программирования интерфейсов — Debounce (отложенное выполнение) через обработчик ожидания. Суть метода заключается в том, что отбор накладывается не моментально при вводе буквы, а только тогда, когда пользователь сделал небольшую паузу в наборе (например, 0.5 секунды).
Рассмотрим по шагам, как это реализовать:
СтрокаПоиска (тип Строка) и вынесем его на форму над динамическим списком в виде поля ввода.ИзменениеТекстаРедактирования.ВременныйТекстПоиска (тип Строка), в котором будем хранить промежуточное состояние ввода.Проанализируем программный код для модуля управляемой формы:
&НаКлиенте
Процедура СтрокаПоискаИзменениеТекстаРедактирования(Элемент, Текст, ОбластьВыбора, СтандартнаяОбработка)
// Сбрасываем таймер ожидания, если пользователь продолжает активно печатать
ОтключитьОбработчикОжидания("ВыполнитьПоискНаСервере");
// Сохраняем текущее состояние текстового поля во временный реквизит формы
ВременныйТекстПоиска = Текст;
// Запускаем обработчик ожидания с задержкой в 0.5 секунды.
// Третий параметр "Истина" указывает, что обработчик выполнится однократно.
ПодключитьОбработчикОжидания("ВыполнитьПоискНаСервере", 0.5, Истина);
КонецПроцедуры
Теперь напишем саму процедуру поиска, которая будет вызываться обработчиком ожидания. Обратите внимание, что наложение отбора должно происходить на сервере, так как динамический список требует работы с его компоновщиком настроек:
&НаКлиенте
Процедура ВыполнитьПоискНаСервере()
// Вызываем серверный метод для установки параметров отбора
УстановитьФильтрСпискаНаСервере(ВременныйТекстПоиска);
// Необязательно: если нужно вернуть фокус в список после окончания ввода,
// раскомментируйте следующую строку:
// Элементы.Список.Активизировать();
КонецПроцедуры
&НаСервере
Процедура УстановитьФильтрСпискаНаСервере(ЗначениеПоиска)
// Получаем группу отбора динамического списка
ОтборСписка = Список.КомпоновщикНастроек.ФиксированныеНастройки.Отбор;
// Ищем ранее созданный элемент отбора, чтобы не дублировать настройки
ИмяПоляКомпоновки = Новый ПолеКомпоновкиДанных("Наименование"); // Поле, по которому ищем
ЭлементОтбора = Неопределено;
Для Каждого Элемент Из ОтборСписка.Элементы Цикл
Если ТипЗнч(Элемент) = Тип("ЭлементОтбораКомпоновкиДанных") И Элемент.ЛевоеЗначение = ИмяПоляКомпоновки Тогда
ЭлементОтбора = Элемент;
Прервать;
КонецЕсли;
КонецЦикла;
// Если элемент отбора не найден, создаем новый
Если ЭлементОтбора = Неопределено Тогда
ЭлементОтбора = ОтборСписка.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = ИмяПоляКомпоновки;
КонецЕсли;
// Если строка поиска пустая, отключаем отбор
Если ПустаяСтрока(ЗначениеПоиска) Тогда
ЭлементОтбора.Использование = Ложь;
Иначе
ЭлементОтбора.Использование = Истина;
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Содержит;
ЭлементОтбора.ПравоеЗначение = ЗначениеПоиска;
КонецЕсли;
КонецПроцедуры
Такой подход позволяет пользователю беспрепятственно вводить наименование товара или контрагента. Как только набор приостанавливается на полсекунды, список мягко обновляется, а фокус ввода остается в поле поиска (или переходит на список, если была раскомментирована строка принудительной активации).
Рассмотрим другую проблему: пользователь воспользовался стандартным поиском платформы (нажал Ctrl + F или просто начал вводить текст на списке), выбрал нужную строку (например, перенес товар в документ двойным кликом), и теперь нам нужно программно сбросить этот отбор, чтобы вернуть список к исходному полному виду.
Сложность заключается в том, что платформенный поиск работает поверх стандартного механизма компоновки данных. Если вы попытаетесь вызвать Список.Отбор.Элементы.Очистить(), это никак не повлияет на системную строку поиска — она останется заполненной, а список — отфильтрованным.
Рассмотрим три варианта решения этой задачи:
Самый надежный и архитектурно правильный способ — полностью запретить использование стандартной строки поиска для конкретной таблицы на форме. Для этого:
ПоложениеСтрокиПоиска и установим его в значение Нет.При таком подходе сброс поиска при выборе элемента или по нажатию кнопки «Очистить» выполняется элементарно в одну строку кода на клиенте:
&НаКлиенте
Процедура СброситьКастомныйПоиск()
СтрокаПоиска = "";
ВременныйТекстПоиска = "";
УстановитьФильтрСпискаНаСервере("");
КонецПроцедуры
Если по каким-то причинам критически важно сохранить именно стандартную поисковую панель 1С, но при этом требуется программно сбрасывать ее результаты, можно воспользоваться эмуляцией нажатия горячих клавиш очистки поиска. В платформе 1С:Предприятие за сброс поиска отвечает сочетание клавиш Ctrl + Q (в зависимости от раскладки клавиатуры и версии платформы также может использоваться Ctrl + Shift + Q).
Мы можем вызвать эту команду программно через интерфейс операционной системы Windows:
&НаКлиенте
Процедура СброситьСтандартныйПоискWindows()
#Если Клиент Тогда
Попытка
// Создаем COM-объект операционной системы для работы со сценариями
Шелл = Новый COMОбъект("Wscript.Shell");
// Обязательно активизируем элемент формы (таблицу списка)
Элементы.Список.Активизировать();
// Посылаем команду нажатия Ctrl + Q для английской раскладки
Шелл.SendKeys("^q");
// Посылаем команду нажатия Ctrl + Й для русской раскладки
Шелл.SendKeys("^й");
Исключение
// Данный код не сработает в веб-клиенте, на MacOS или Linux
КонецПопытки;
#КонецЕсли
КонецПроцедуры
Важное предупреждение: данный метод является нестабильным обходным путем (workaround). Он зависит от текущей раскладки клавиатуры пользователя, загруженности процессора и операционной системы. Использовать его рекомендуется только в крайних случаях, когда другие варианты невозможны.
Если требуется гарантированно очистить все кэшированные платформой отборы и настройки поиска, но при этом недопустимо использовать внешние COM-объекты, можно прибегнуть к переоткрытию формы. При закрытии и повторном открытии формы с передачей ключа текущего объекта для позиционирования платформа полностью пересоздает контекст, стирая историю поиска.
Однако помните, что этот метод приводит к визуальному «миганию» экрана и создает дополнительную нагрузку на сервер СУБД, так как форма инициализируется заново. Используйте его только тогда, когда чистота интерфейса важнее производительности.
Мы подробно проанализировали особенности работы с поиском в динамических списках. Рекомендуем по возможности отдавать приоритет первому варианту — проектированию собственного кастомного поиска с использованием обработчика ожидания. Это гарантирует стабильную кроссплатформенную работу вашей конфигурации в любых тонких и веб-клиентах, а также обеспечит максимальный комфорт для пользователей.