При проектировании интерфейсов в управляемом приложении 1С разработчики часто сталкиваются с неприятным поведением платформы: при попытке выполнить поиск или установить отбор на форме с несколькими страницами (вкладками), фокус автоматически сбрасывается, и система принудительно переключает пользователя на самую первую страницу. Давайте подробно разберем, почему возникает эта проблема, проанализируем внутренние механизмы платформы 1С и рассмотрим три практических сценария решения этой задачи в соответствии с современными стандартами разработки.
В управляемой форме 1С один из реквизитов всегда назначается основным реквизитом формы (в списках документов это, как правило, динамический список Список или ДокументСписок). Это критически важно для работы стандартных механизмов платформы. Когда мы размещаем на нескольких страницах панели разные таблицы, связанные с разными динамическими списками, возникает конфликт фокуса:
Разберем три наиболее эффективных способа решения этой проблемы, начиная с рекомендуемого стандарта фирмы «1С».
Создание нескольких динамических списков под каждый статус — ресурсоемкий подход. Он перегружает сервер лишними запросами, усложняет поддержку кода и приводит к неоправданному расходу оперативной памяти. Фирма «1С» в стандартах разработки (интерфейс «Такси») рекомендует использовать один динамический список и быстрый отбор с помощью элемента управления типа «Тумблер».
Давайте по шагам разберем, как реализовать этот механизм:
Список и одну таблицу, отображающую его. Никаких вкладок и страниц для разделения списков создавать не нужно.ОтборСтатус. В качестве типа данных выберем ссылку на соответствующий справочник, перечисление (например, ПеречислениеСсылка.СтатусыДокументов) или простую строку.ОтборСтатус на форму в область над таблицей динамического списка.ОтборСтатус обработчик события ПриИзменении.Теперь напишем программный код, который будет быстро и корректно управлять отбором без перезапуска формы и лишних запросов к базе данных. Для этого мы задействуем функции Библиотеки Стандартных Подсистем (БСП):
&НаКлиенте
Процедура ОтборСтатусПриИзменении(Элемент)
УстановитьОтборПоСтатусуНаСервере();
КонецПроцедуры
&НаСервере
Процедура УстановитьОтборПоСтатусуНаСервере()
// Проверим, выбрано ли конкретное значение статуса для фильтрации
Если ЗначениеЗаполнено(ОтборСтатус) Тогда
// Используем БСП для быстрой установки элемента отбора
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
Список,
"Статус",
ОтборСтатус,
ВидСравненияКомпоновкиДанных.Равно,
"ОтборПоСтатусу", // Имя группы/элемента для последующего быстрого поиска
Истина // Использовать этот отбор
);
Иначе
// Если выбрано значение "Все" (пустой статус), полностью удаляем отбор
ОбщегоНазначенияКлиентСервер.УдалитьЭлементыОтбораДинамическогоСписка(
Список,
"Статус"
);
КонецЕсли;
КонецПроцедуры
Преимущества данного подхода: Интерфейс мгновенно реагирует на действия пользователя. Стандартные команды поиска и отбора работают корректно, фокус не теряется, а база данных не нагружается созданием множества тяжелых динамических списков.
Если по требованиям заказчика или согласно разработанному юзабилити-дизайну интерфейса вам необходимо оставить именно вкладки (страницы), а не тумблер, мы все равно можем применить оптимизированный подход с одним динамическим списком.
Проанализируем этот сценарий по шагам:
СтраницаНовые, СтраницаВРаботе, СтраницаАрхив).Список разместите на форме непосредственно под группой страниц (или над ней, в зависимости от компоновки интерфейса).ПриСменеСтраницы. При клике на вкладку мы будем программно менять отбор в нашем единственном списке.Рассмотрим пример реализации программного кода для этого варианта:
&НаКлиенте
Процедура ГруппаСтраницыПриСменеСтраницы(Элемент, ТекущаяСтраница)
УстановитьОтборПриСменеВкладкиНаСервере(ТекущаяСтраница.Имя);
КонецПроцедуры
&НаСервере
Процедура УстановитьОтборПриСменеВкладкиНаСервере(ИмяВкладки)
// Определяем необходимый статус в зависимости от имени активированной страницы
ТекущийСтатус = Неопределено;
Если ИмяВкладки = "СтраницаНовые" Тогда
ТекущийСтатус = ПредопределенноеЗначение("Перечисление.СтатусыДокументов.Новый");
ИначеЕсли ИмяВкладки = "СтраницаВРаботе" Тогда
ТекущийСтатус = ПредопределенноеЗначение("Перечисление.СтатусыДокументов.ВРаботе");
ИначеЕсли ИмяВкладки = "СтраницаАрхив" Тогда
ТекущийСтатус = ПредопределенноеЗначение("Перечисление.СтатусыДокументов.Архив");
КонецЕсли;
// Применяем отбор к нашему единственному списку
Если ЗначениеЗаполнено(ТекущийСтатус) Тогда
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
Список,
"Статус",
ТекущийСтатус,
ВидСравненияКомпоновкиДанных.Равно,
"ОтборПоСтатусу",
Истина
);
Иначе
// Если перешли на вкладку "Все", очищаем фильтр по статусу
ОбщегоНазначенияКлиентСервер.УдалитьЭлементыОтбораДинамическогоСписка(Список, "Статус");
КонецЕсли;
КонецПроцедуры
При использовании этого метода пользователь визуально переключается по вкладкам, но физически таблица на форме остается одна. Следовательно, стандартные механизмы поиска работают без сброса фокуса и без неконтролируемого переключения страниц.
Бывают сложные архитектурные задачи, когда на разных страницах должны отображаться принципиально разные данные, которые невозможно объединить в рамки одного динамического списка (например, на первой вкладке отображаются «Заказы клиентов», а на второй — «Заявки на возврат товаров»).
В этом случае, чтобы избежать «прыжков» интерфейса, нам необходимо изолировать командные панели и связать их с конкретными таблицами формы. Выполним следующие настройки:
Автозаполнение установим в значение Ложь). Это предотвратит появление глобальных кнопок поиска, ориентированных только на основной реквизит формы.Группа - Командная панель).ИсточникДействий — выберем соответствующую таблицу этой страницы (например, ТаблицаЗаказы или ТаблицаВозвраты).Автозаполнение в значение Истина. Теперь стандартные кнопки «Найти» и «Отбор» будут жестко привязаны к конкретной таблице на активной вкладке и не вызовут переключения фокуса на первую страницу формы.Для обеспечения максимального удобства работы пользователя мы можем программно синхронизировать отборы между этими независимыми списками. Допустим, если пользователь установил отбор по контрагенту на одной вкладке, мы можем транслировать его на все остальные вкладки. Для этого мы задействуем метод формы ПодключитьОбработчикИзмененияДанных, который позволит отслеживать изменения состава отбора в активном списке и своевременно передавать параметры в соседние списки формы.
Выбор конкретного решения всегда зависит от специфики вашей конфигурации, однако применение одного динамического списка в сочетании с переключателем-тумблером во многих случаях является наиболее надежным, быстрым и удобным для конечного пользователя решением.