Как программно перейти в конец динамического списка в 1С при изменении сортировки

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

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

Анализируем проблему: почему свойство НачальноеОтображениеСписка не помогает

В платформе 1С существует стандартное свойство элемента формы «Динамический список» — НачальноеОтображениеСписка. Оно может принимать значения НачалоСписка, КонецСписка или Авто. Казалось бы, достаточно установить его в значение «Конец списка», и задача решена. Однако здесь есть важный технический нюанс.

Проанализируем ситуацию: данное свойство отрабатывает только в момент инициализации (первого открытия) формы. Если форма уже открыта, и мы программно меняем настройки списка (отборы, группировки или сортировку), платформа стремится сохранить контекст пользователя. Это означает, что курсор останется на той же строке, на которой он был до изменения настроек, если эта строка все еще присутствует в выборке. Прыжка «вниз» автоматически не произойдет. Чтобы добиться нужного поведения, нам придется реализовать алгоритм позиционирования самостоятельно.

Выясняем причину: динамическая природа списка

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

Следовательно, мы не можем просто обратиться к свойству типа Количество() или индексу последней строки. Для решения задачи нам необходимо точно определить ключ записи, которая при текущих настройках окажется последней.

Разберем по шагам основной способ: поиск ключа через запрос

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

  1. Получаем текущие настройки: Нам нужно учесть все активные отборы, которые наложил пользователь или система, чтобы наш запрос искал по той же выборке данных.
  2. Формируем запрос: Мы берем текст запроса из настроек динамического списка.
  3. Инвертируем сортировку: Если в списке установлена сортировка по дате (возрастание), в нашем запросе мы должны установить сортировку по дате (убывание). Таким образом, «последняя» запись списка станет «первой» в нашем запросе.
  4. Ограничиваем выборку: Используем конструкцию ПЕРВЫЕ 1, чтобы не нагружать систему.
  5. Устанавливаем позицию: Полученную ссылку (или ключ) передаем в элемент формы.

Посмотрим на пример реализации такого метода в коде:


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

КонецПроцедуры

Проанализируем ситуацию с программной установкой ТекущейСтроки

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

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

Пример клиентского кода:


&НаКлиенте
Процедура УстановитьСортировкуИПерейтиВКонец()
    
    // 1. Программная смена сортировки
    НастройкаПорядка = Список.КомпоновщикНастроек.Настройки.Порядок.Элементы.Добавить(Тип("ЭлементПорядкаКомпоновкиДанных"));
    НастройкаПорядка.Поле = Новый ПолеКомпоновкиДанных("Дата");
    НастройкаПорядка.ТипУпорядочивания = ТипУпорядочиванияКомпоновкиДанных.Возр;
    
    // 2. Получаем ссылку на последнюю строку (вызов серверной функции, описанной выше)
    ПоследняяСсылка = ПолучитьКлючПоследнейЗаписиНаСервере();
    
    // 3. Устанавливаем строку
    Элементы.Список.ТекущаяСтрока = ПоследняяСсылка;
    
КонецПроцедуры

Рассмотрим альтернативу: инверсия сортировки как бизнес-решение

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

Вместо того чтобы заставлять систему искать последнюю строку и прокручивать список, зачастую правильнее настроить сортировку по убыванию даты. В этом случае новые записи всегда будут находиться в самом верху (в начале списка). Это стандарт поведения для большинства современных ERP-систем. Такой подход:

Подведем итоги

Мы выяснили, что переход в конец динамического списка — это задача, требующая понимания механизмов компоновки данных и клиент-серверного взаимодействия. Если бизнес-логика требует именно такого поведения, используйте метод с обратным запросом (ПЕРВЫЕ 1) и установкой ТекущаяСтрока. Но всегда помните о возможности инвертировать сортировку, чтобы сделать работу со списком более естественной для платформы 1С.

← На главную