Как отключить центрирование и «прыжки» текущей строки в табличной части управляемой формы 1С?

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

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

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

Выясняем причину: почему строка «прыгает» в центр?

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

Существует несколько основных триггеров, которые запускают этот нежелательный механизм в событии ПриАктивизацииСтроки табличной части:

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

Способ 1. Использование реквизитов формы вместо свойств элементов (Решение без перерисовки)

Рассмотрим ситуацию, когда при активизации строки нам необходимо вывести подробное текстовое описание или статус текущего номенклатурного узла под табличной частью. Обычное решение начинающего разработчика выглядит так:


&НаКлиенте
Процедура ТоварыПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элемент.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        // ОШИБКА: Прямое изменение свойства элемента интерфейса вызывает прыжок строки!
        Элементы.ДекорацияСтатус.Заголовок = "Выбран товар: " + ТекущиеДанные.Номенклатура;
    КонецЕсли;
КонецПроцедуры

Чтобы избежать перерисовки формы, мы должны заменить прямое изменение элемента формы на изменение связанного реквизита. Разберем этот процесс по шагам:

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

Посмотрим на пример правильной реализации:


&НаКлиенте
Процедура ТоварыПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элемент.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        // ПРАВИЛЬНО: Изменение значения реквизита не приводит к пересчету геометрии всей формы
        ИнформационнаяСтрока = "Выбран товар: " + ТекущиеДанные.Номенклатура;
    КонецЕсли;
КонецПроцедуры

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


Способ 2. Оптимальная схема с обработчиком ожидания и кэшированием

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

Просто вызвать обработчик ожидания недостаточно — без проверки кэша событие может зацикливаться или выполняться избыточное количество раз при обычном скроллинге. Разберем эффективный и надежный алгоритм.

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

Реализуем следующий код в модуле управляемой формы:


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

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

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


Способ 3. Переход на безконтекстные серверные вызовы

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

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


// НЕПРАВИЛЬНО: Вызов тянет за собой всю форму
&НаСервере
Функция ПолучитьОстатокНаСкладеКонтекст(Номенклатура)
    Возврат РегистрыНакопления.ТоварыНаСкладах.Остатки(,, Новый Структура("Номенклатура", Номенклатура)).Итог("Количество");
КонецФункции

// ПРАВИЛЬНО: Легкий вызов, не вызывающий перерисовку интерфейса на клиенте
&НаСервереБезКонтекста
Функция ПолучитьОстатокНаСкладеБезКонтекста(Знач Номенклатура)
    Возврат РегистрыНакопления.ТоварыНаСкладах.Остатки(,, Новый Структура("Номенклатура", Номенклатура)).Итог("Количество");
КонецФункции

При использовании функции ПолучитьОстатокНаСкладеБезКонтекста клиентское приложение передает на сервер только один конкретный параметр (ссылку на номенклатуру), а обратно получает лишь числовое значение. Данные формы при этом остаются нетронутыми, макет таблицы не пересчитывается, и строка стабильно остается на своем месте.


Способ 4. Альтернатива для экстремальных объемов данных (3000+ строк)

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

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

← На главную