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

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

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

Почему «теряется» текущая строка?

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

Именно поэтому попытка просто сохранить старое значение свойства Элементы.ИмяТаблицы.ТекущаяСтрока в переменную и присвоить его обратно после обновления не сработает — этот идентификатор больше не существует в контексте формы.

Алгоритм восстановления позиции курсора

Для решения задачи нам необходимо реализовать следующую последовательность действий:

  1. Перед началом обновления данных сохранить значения ключевых полей, которые однозначно идентифицируют строку (например, «Артикул», «Код» или уникальный идентификатор строки).
  2. Выполнить обновление данных на сервере.
  3. После возврата на клиент найти новую строку в обновленной коллекции по сохраненным ключевым полям.
  4. Получить новый идентификатор найденной строки.
  5. Установить этот идентификатор в свойство ТекущаяСтрока.

Рассмотрим подробнее каждый этап реализации.

Решение №1: Поиск по ключевым реквизитам (Рекомендуемое)

Проанализируем ситуацию, когда в нашей таблице есть колонка с уникальным значением, например, Номенклатура или скрытая колонка КлючСвязи. Это самый надежный способ, так как он не зависит от сортировки таблицы.


&НаКлиенте
Процедура ОбновитьДанныеИТантановитьКурсор()
    
    // 1. Запоминаем данные текущей строки
    ТекущиеДанные = Элементы.ТЗ.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Сохраняем уникальный ключ (например, ссылку на товар или ID)
    СохраненныйКлюч = ТекущиеДанные.Номенклатура; 
    
    // 2. Вызываем серверный метод обновления
    ОбновитьТаблицуНаСервере();
    
    // 3. Ищем строку в обновленной коллекции (ТЗ - это реквизит формы)
    ПараметрыПоиска = Новый Структура("Номенклатура", СохраненныйКлюч);
    НайденныеСтроки = ТЗ.НайтиСтроки(ПараметрыПоиска);
    
    Если НайденныеСтроки.Количество() > 0 Тогда
        // 4. Получаем новый идентификатор и устанавливаем позицию
        НоваяСтрока = НайденныеСтроки[0];
        Элементы.ТЗ.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();
        
        // Дополнительно: обеспечиваем видимость строки
        Элементы.ТЗ.ВыделитьВыделенныеСтроки();
    КонецЕсли;
    
КонецПроцедуры

Обратите внимание, что на клиенте у объекта ДанныеФормыКоллекция метод НайтиСтроки возвращает массив объектов ДанныеФормыЭлементКоллекции, у которых есть встроенный метод ПолучитьИдентификатор(). Это именно то, что нам нужно для свойства ТекущаяСтрока.

Решение №2: Использование индекса строки

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


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

Важный нюанс: Возврат фокуса (активация элемента)

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

Рассмотрим, как это сделать:


// После установки текущей строки принудительно переносим фокус на таблицу
Элементы.ТекущийЭлемент = Элементы.ТЗ;

Важно: свойство ТекущийЭлемент формы принимает сам объект элемента (кнопку, таблицу, поле ввода), а не идентификатор строки. Это «оживляет» таблицу для управления с клавиатуры.

Комплексный пример в обработчике события «Выбор»

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


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

Заключение и рекомендации

Мы проанализировали основные способы позиционирования курсора в управляемых формах 1С 8.3. Подведем итоги:

  1. Никогда не полагайтесь на сохранение самого идентификатора строки (целого числа) между серверными вызовами с обновлением реквизита — он гарантированно изменится.
  2. Всегда создавайте в таблице «технический» уникальный ключ (например, колонку с типом Число или УникальныйИдентификатор), если в данных нет естественного ключа.
  3. Для установки курсора используйте метод ПолучитьИдентификатор() у найденного элемента коллекции ДанныеФормыКоллекция.
  4. Не забывайте использовать Элементы.ТекущийЭлемент, чтобы вернуть пользователю возможность работать с клавиатурой сразу после обновления данных.

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

← На главную