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

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

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

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

Прежде всего, нам необходимо понять внутреннюю механику платформы. В управляемых формах у каждой строки ДанныеФормыКоллекция (которой является таблица на форме) есть два типа «адреса»:

  1. Индекс — порядковый номер строки в коллекции (начинается с 0).
  2. Идентификатор строки — внутреннее целое число, которое платформа присваивает строке при её создании в памяти текущего сеанса.

Когда мы вызываем методы типа Загрузить() или полностью обновляем таблицу на сервере, старые объекты строк уничтожаются, а новые создаются «с нуля». Даже если данные в строке остались прежними, её внутренний идентификатор меняется. Свойство таблицы ТекущаяСтрока хранит именно этот внутренний идентификатор. Поскольку старого идентификатора больше не существует, платформа не находит его в новой коллекции и устанавливает фокус на начало списка.

Шаг 1. Сохранение «бизнес-ключа» строки

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

Перед началом обновления данных на клиенте нам нужно запомнить значение этого ключа:


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

    // 2. Вызываем серверную процедуру обновления
    ОбновитьДанныеНаСервере();
    
    // 3. Переходим к поиску и позиционированию (см. Шаг 2)
    ПозиционироватьНаСтроку(КлючСтроки);

КонецПроцедуры

Шаг 2. Обновление данных и использование ЗначениеВРеквизитФормы

Как показывает практика, использование простого метода Загрузить() для таблицы значений иногда приводит к тому, что визуальная часть формы не успевает корректно отработать изменения. Рассмотрим более надежный способ через работу с объектом и преобразование его в реквизит формы.


&НаСервере
Процедура ОбновитьДанныеНаСервере()
    
    Запрос = Новый Запрос("ВЫБРАТЬ * ИЗ РегистрСведений.НашРегистр ГДЕ ...");
    ТаблицаРезультат = Запрос.Выполнить().Выгрузить();
    
    // Использование ЗначениеВРеквизитФормы часто работает стабильнее, 
    // так как платформа более явно отслеживает изменение коллекции
    ЗначениеВРеквизитФормы(ТаблицаРезультат, "ДанныеСписка");
    
КонецПроцедуры

Шаг 3. Поиск новой строки и установка фокуса

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


&НаКлиенте
Процедура ПозиционироватьНаСтроку(КлючСтроки)
    
    Если КлючСтроки = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Ищем строки в коллекции по нашему бизнес-ключу
    ПараметрыПоиска = Новый Структура("ИдентификаторЗаписи", КлючСтроки);
    НайденныеСтроки = ДанныеСписка.НайтиСтроки(ПараметрыПоиска);
    
    Если НайденныеСтроки.Количество() > 0 Тогда
        // Получаем ПЕРВУЮ найденную строку (объект ДанныеФормыЭлементКоллекции)
        СтрокаКоллекции = НайденныеСтроки[0];
        
        // Важный момент: устанавливаем ТекущуюСтроку через внутренний идентификатор
        Элементы.ДанныеСписка.ТекущаяСтрока = СтрокаКоллекции.ПолучитьИдентификатор();
    КонецЕсли;
    
КонецПроцедуры

Решение проблемы «двойного выделения» и фантомного фокуса

Часто разработчики жалуются: «Я установил ТекущаяСтрока, строка выделилась цветом, но пунктирная рамка (фокус) всё равно осталась на первой строке или выделились сразу две». Это происходит из-за рассинхронизации визуального состояния таблицы и данных.

Чтобы этого избежать, проанализируем следующие рекомендации:

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

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

← На главную