Как сделать, чтобы таблица на управляемой форме не вставала в начало после обновления данных?

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

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

Почему таблица «прыгает» и теряет позицию?

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

  1. Программное изменение текста подвала: Это самая частая причина. Если вы напрямую присваиваете значение свойству Элементы.ИмяТаблицыКолонка.ТекстПодвала, платформа инициирует обновление всей структуры таблицы, что приводит к скроллу в начало.
  2. Полная перезагрузка данных: Использование методов типа Загрузить() для табличных частей или полное обновление запроса в динамическом списке уничтожает старые идентификаторы строк.
  3. Контекстные серверные вызовы: Когда выполнение уходит на сервер (&НаСервере) внутри обработчика события, платформа пытается восстановить состояние формы при возврате на клиент. Если данных много или структура изменилась, алгоритм восстановления может сработать некорректно.
  4. Преобразование данных: Использование связки РеквизитФормыВЗначение и затем ЗначениеВРеквизитФормы полностью пересоздает объектную структуру данных формы.

Решение 1: Правильное использование свойства «ПутьКДаннымПодвала»

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

Разберем по шагам, как это реализовать:

  1. Создадим в Реквизитах формы новый реквизит (например, с именем ИтогКоличество и типом Число).
  2. В окне элементов формы выберем нужную колонку таблицы.
  3. В палитре свойств найдем поле ПутьКДаннымПодвала (PathToDataFooter) и выберем наш новый реквизит ИтогКоличество.
  4. В коде, где происходит расчет суммы или количества, будем просто присваивать значение этому реквизиту.

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


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

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

Решение 2: Работа с идентификаторами строк

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

Проанализируем пример кода, который позволяет «запомнить» строку перед обновлением и «вернуться» на нее после:


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

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

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

Часто проблема возникает из-за избыточного использования контекстных серверных вызовов. Рассмотрим, как минимизировать влияние сервера на интерфейс. Выясним причину: при вызове &НаСервере на сервер передается весь контекст формы (все данные всех реквизитов), а при возврате — вся форма обновляется.

Попробуем использовать внеконтекстные вызовы (&НаСервереБезКонтекста). Это работает значительно быстрее и стабильнее для интерфейса:


&НаКлиенте
Процедура ПриИзмененииДанных(Элемент)
    
    ТекДанные = Элементы.Таблица.ТекущиеДанные;
    
    // Передаем только необходимые параметры, а не всю форму
    РезультатРасчета = РассчитатьНаСервереБезКонтекста(ТекДанные.Номенклатура, ТекДанные.Количество);
    
    ТекДанные.Результат = РезультатРасчета;
    
КонецПроцедуры

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

Решение 4: Принудительное управление фокусом и отображением

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

В конце вашего обработчика ПриИзменении добавьте следующую строку:


// Возвращаем фокус на тот же элемент, который инициировал изменение
ЭтаФорма.ТекущийЭлемент = Элемент;

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

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

Чтобы ваша таблица работала стабильно и не раздражала пользователя «прыжками»:

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

← На главную