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