Почему сбрасывается текущая строка при активизации в динамическом списке и как это исправить?

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

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

В этой статье мы подробно разберем причины такого поведения платформы 1С и рассмотрим проверенные способы устранения проблемы.

Причины лишних срабатываний события и сброса выделения

Выделим основные технические причины, по которым событие ПриАктивизацииСтроки начинает зацикливаться или сбрасывать выделенную строку:

  1. Контекстные серверные вызовы. Если прямо из клиентской процедуры ПриАктивизацииСтроки вызывать серверный контекст (процедуру с директивой &НаСервере), платформа передает весь контекст формы на сервер и возвращает его обратно. При этом данные формы обновляются, что провоцирует повторную активизацию элементов.
  2. Изменение свойств элементов формы (видимость, доступность). Изменение доступности или видимости полей на клиенте заставляет платформу пересчитывать геометрический макет интерфейса и производить перерисовку элементов. Это действие может неявно инициировать обновление динамического списка и повторный вызов активизации строки.
  3. Сброс кеша данных динамического списка. Если при смене строки происходит изменение реквизитов или отборов, связанных со списком, список считает текущий идентификатор строки недействительным и автоматически переводит курсор на первую строку.

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

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

Рассмотрим пример реализации:


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    // Отключаем предыдущий обработчик, если он был запущен
    ОтключитьОбработчикОжидания("ОбработатьСменуСтроки");
    
    // Подключаем однократный обработчик с задержкой 0.1 секунды
    ПодключитьОбработчикОжидания("ОбработатьСменуСтроки", 0.1, Истина);
КонецПроцедуры

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

Решение 2: Проверка фактического изменения строки на клиенте

Чтобы избежать выполнения тяжелого кода при повторных или ложных срабатываниях события, рекомендуется сохранять идентификатор последней обработанной строки в переменной или реквизите формы и сравнивать его с текущей строкой.

Проанализируем пример кода с запоминанием идентификатора:


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

Решение 3: Оптимизация серверных вызовов через бесконтекстные функции

Если при смене строки вам необходимо получить детальные данные по выделенной записи с сервера, категорически избегайте контекстных вызовов. Используйте директиву &НаСервереБезКонтекста и передавайте только идентификатор строки или ключ данных.

Для получения идентификатора текущей строки динамического списка на клиенте обратитесь к функции ПолучитьИдентификатор() объекта ТекущиеДанные:


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Получаем значение ключа или идентификатора строки
    ИдентификаторЗаписи = ТекущиеДанные.Ссылка;
    
    // Бесконтекстный вызов сервера не передает форму и не вызывает перерисовку списка
    ДетальнаяИнформация = ПолучитьСведенияНаСервере(ИдентификаторЗаписи);
    ЗаполнитьПоляФормы(ДетальнаяИнформация);
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьСведенияНаСервере(СсылкаНаОбъект)
    // Выполнение запроса или получение данных без передачи контекста формы
    Возврат Результат;
КонецФункции

Применяя комбинацию обработчика ожидания, проверки идентификатора строки на клиенте и бесконтекстных вызовов сервера, вы полностью исключите зацикливание события ПриАктивизацииСтроки и сброс позиционирования в динамическом списке.

← На главную