Почему зацикливается событие ПриАктивизацииСтроки динамического списка и как это исправить

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

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

Причины возникновения бесконечного цикла

Рассмотрим, что происходит «под капотом» управляемой формы в момент активации строки динамического списка:

  1. Перерисовка интерфейса при изменении свойства Видимость: когда в обработчике события выполняется код вида Элементы.Кнопка.Видимость = Ложь;, клиентское приложение пересчитывает компоновку элементов формы. Изменение состава отображаемых элементов приводит к смещению фокуса и повторному вызову событий интерфейса, в том числе ПриАктивизацииСтроки. Это замыкает бесконечный цикл: активация строки вызывает изменение видимости, изменение видимости провоцирует перерисовку, а перерисовка снова активирует строку.
  2. Скрытые и явные серверные вызовы: вызов функций с директивами &НаСервере или &НаСервереБезКонтекста при каждом перемещении курсора блокирует пользовательский интерфейс и при медленном соединении может вызывать каскадное накопление очереди событий платформы.
  3. Отсутствие проверки смены строки: событие ПриАктивизацииСтроки генерируется платформой не только при реальном переходе на другую запись, но и при обновлении данных формы, смене фокуса между элементами или обновлении динамического списка.

Способ 1. Замена управления видимостью на управление доступностью

Самое быстрое и эффективное исправление проблемы зацикливания — отказаться от постоянного изменения свойства Видимость элементов формы при навигации по строкам. Вместо этого используем свойство Доступность (или ТолькоПросмотр для полей ввода). Изменение доступности делает элемент неактивным (серым), но не изменяет геометрию формы и не инициирует повторную перерисовку контейнеров.

Посмотрим на пример переработки кода:


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Вместо изменения свойства Видимость управляем свойством Доступность
    Элементы.КнопкаСогласовать.Доступность = ТекущиеДанные.ЕстьКонструктор;
КонецПроцедуры

Способ 2. Перенос вычисляемых проверок в запрос динамического списка

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

Оптимальное решение — перенести проверку непосредственно в текст запроса динамического списка. Разберем реализацию по шагам:

  1. Открываем форму списка и заходим в свойства динамического списка.
  2. В тексте запроса добавляем вычисляемое булево поле:
    
    ВЫБОР
        КОГДА ДокументРазработка.ОтветственныйКонструктор <> ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка)
            ТОГДА ИСТИНА
        ИНАЧЕ ЛОЖЬ
    КОНЕЦ КАК ЕстьКонструктор
    
  3. В настройках динамического списка для нового поля ЕстьКонструктор устанавливаем флаг Использовать всегда, чтобы платформа всегда передавала его на клиентскую сторону.
  4. Теперь значение доступно на клиенте мгновенно через Элементы.Список.ТекущиеДанные.ЕстьКонструктор без единого обращения к серверу.

Способ 3. Кэширование прав и статических параметров при открытии формы

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

Разберем пример реализации:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Сохраняем права в реквизит формы (например, флаг ПравоРедактирования)
    ПравоРедактирования = РольДоступна("ПолныеПрава") Или РольДоступна("ОтветственныйКонструктор");
КонецПроцедуры

&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    Если Элементы.Список.ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Используем уже вычисленный реквизит формы на клиенте
    Элементы.КнопкаДействие.Доступность = ПравоРедактирования И Элементы.Список.ТекущиеДанные.ЕстьКонструктор;
КонецПроцедуры

Способ 4. Фиксация предыдущей строки и программный семафор

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

Посмотрим на пример организации модуля формы:


&НаКлиенте
Перем ПредыдущаяСтрока;
&НаКлиенте
Перем ИдетОбработкаСтроки;

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

    ТекущаяСтрока = Элемент.ТекущаяСтрока;
    
    // Если пользователь остался на той же строке - ничего не делаем
    Если ТекущаяСтрока = ПредыдущаяСтрока Тогда
        Возврат;
    КонецЕсли;

    ИдетОбработкаСтроки = Истина;
    
    Попытка
        ПредыдущаяСтрока = ТекущаяСтрока;
        
        Если Элементы.Список.ТекущиеДанные <> Неопределено Тогда
            Элементы.КомандаОбработать.Доступность = Элементы.Список.ТекущиеДанные.ЕстьКонструктор;
        КонецЕсли;
    Исключение
        ИдетОбработкаСтроки = Ложь;
        ВызватьИсключение;
    КонецПопытки;
    
    ИдетОбработкаСтроки = Ложь;
КонецПроцедуры

Способ 5. Использование обработчика ожидания

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

Рассмотрим, как устроен этот механизм:


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

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

    // Выполняем настройку элементов формы
    Элементы.ГруппаДействий.Доступность = ТекущиеДанные.ЕстьКонструктор;
КонецПроцедуры

Сводные рекомендации

  1. Не меняйте свойство Видимость в обработчиках движения по списку. Используйте Доступность.
  2. Откажитесь от серверных вызовов внутри ПриАктивизацииСтроки. Переносите вычисления в поля динамического списка или кэшируйте их в ПриСозданииНаСервере.
  3. Всегда проверяйте ТекущиеДанные на равенство Неопределено во избежание ошибок при пустом списке или асинхронном получении данных платформой.
← На главную