Как предотвратить автоскролл и прыжки таблицы при изменении элементов управляемой формы

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

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

Выясняем причину: механизмы отрисовки и Layout

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

Когда мы выполняем команды Элементы.Добавить() или Элементы.Удалить(), мы фактически меняем структуру дерева элементов формы. Это заставляет платформу инициировать процесс полной перекомпоновки макета (Layout). Во время этого процесса происходит следующее:

  1. Контейнеры формы пересчитывают свои размеры.
  2. Таблица на мгновение может потерять точные координаты своего скролла.
  3. Чтобы гарантировать, что пользователь не «потеряет» фокус, платформа вызывает стандартный алгоритм обеспечения видимости текущей строки.
  4. Этот алгоритм по умолчанию стремится поместить ТекущаяСтрока в центр таблицы, если ее положение кажется движку «нестабильным».

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

Метод 1: Использование свойства Видимость вместо пересоздания элементов

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

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


// Вместо этого:
НовыйЭлемент = Элементы.Добавить("ПолеВводаСумма", Тип("ПолеФормы"), ЭтаФорма);

// Используем это:
Элементы.ПолеВводаСумма.Видимость = Истина;

Метод 2: Фиксация высоты контейнера

Часто автоскролл провоцируется тем, что при появлении нового элемента (например, информационной надписи над таблицей) высота самой таблицы уменьшается на несколько пикселей. Рассмотрим ситуацию: таблица растянута по вертикали, и любое изменение размеров соседей заставляет её «пересчитывать» видимые строки.

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

Метод 3: Использование обработчика ожидания и метода ПоказатьСтроку

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

Разберем по шагам реализацию этого механизма:

  1. Перед тем как изменять состав элементов, запоминаем текущую строку таблицы.
  2. Выполняем действия по добавлению/удалению элементов.
  3. Подключаем обработчик ожидания с минимальным интервалом (например, 0.1 секунды).

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

&НаКлиенте
Процедура ВосстановитьПозициюТаблицы()
    // Платформа уже перерисовала форму и, возможно, сдвинула скролл.
    // Попробуем принудительно показать строку.
    Элементы.ТаблицаТовары.ПоказатьСтроку(Элементы.ТаблицаТовары.ТекущаяСтрока);
КонецПроцедуры

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

Метод 4: Трюк с «Верхней строкой»

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

К сожалению, программно определить, какая строка сейчас первая сверху в УФ, практически невозможно без использования внешних компонент. Но если ваша логика позволяет вычислить индекс первой видимой строки (например, вы знаете, что пользователь пролистывает данные постранично или по определенным группам), вы можете сначала вызвать ПоказатьСтроку() для этой «воображаемой верхней» строки, а затем — для реальной текущей. Это заставит скролл позиционироваться более предсказуемо.

Влияние свойств растягивания

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

Рекомендуем придерживаться следующей структуры для стабильности интерфейса:

Итоги проделанной работы

Подводя итоги, стоит признать, что «чертов автоскролл» — это следствие декларативной природы управляемого интерфейса 1С. Платформа сама решает, как лучше показать данные, исходя из доступного места. Чтобы минимизировать «прыжки»:

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

Эти методы не дают 100% гарантии в веб-клиенте из-за особенностей рендеринга DOM-дерева браузерами, но в тонком клиенте позволяют добиться значительно более плавного поведения интерфейса.

← На главную