Свойство ТекущаяСтрока табличного поля: чтение, установка и навигация
Содержание
Пользователь добавил в документ 40 строк товаров, нажал кнопку «Заполнить цены», а после обработки курсор улетел на первую строку. Чтобы вернуть его на место, нужно запомнить и потом установить свойство ТекущаяСтрока у элемента формы ТаблицаФормы: Элементы.Товары.ТекущаяСтрока = Идентификатор.
Главное отличие от старых обычных форм: в управляемой форме ТекущаяСтрока хранит не саму строку, а её идентификатор (число). Для динамического списка — ссылку или ключ записи. Отсюда растёт большинство ошибок, поэтому ниже всё разобрано по типам данных и с рабочим кодом для платформы 8.3.
Как устроено свойство ТекущаяСтрока
Свойство принадлежит элементу формы (таблице), а не реквизиту. Реквизит — это данные (Объект.Товары), элемент — их отображение (Элементы.Товары). Курсор есть только у элемента.
Что лежит в ТекущаяСтрока, зависит от того, к чему привязана таблица:
| Источник данных таблицы | Тип значения ТекущаяСтрока | Как получить данные строки |
|---|---|---|
Табличная часть объекта (Объект.Товары) | Число — идентификатор строки | Объект.Товары.НайтиПоИдентификатору(Ид) |
| Реквизит формы типа ТаблицаЗначений | Число — идентификатор | ТаблицаРеквизит.НайтиПоИдентификатору(Ид) |
| Реквизит типа ДеревоЗначений | Число — идентификатор | Дерево.НайтиПоИдентификатору(Ид) |
| Динамический список справочника, документа | Ссылка на объект | Сама ссылка, данные — через ТекущиеДанные |
| Динамический список регистра сведений | Ключ записи регистра | ТекущиеДанные или ключ |
| Табличное поле обычной формы | Сама строка (СтрокаТабличнойЧасти, СтрокаТаблицыЗначений) | Напрямую |
Если курсора нет (таблица пустая, строка ещё не выбрана), значение равно Неопределено.
Рядом живут ещё три свойства, которые часто путают:
- 📍
ТекущаяСтрока— где стоит курсор. Можно читать и записывать. - 📄
ТекущиеДанные— данные строки под курсором. Само свойство только для чтения, а поля внутри него можно менять. - ✅
ВыделенныеСтроки— массив идентификаторов (или ссылок) всех выделенных строк при множественном выделении. - 🎯
ТекущийЭлемент— у таблицы это текущая колонка, у формы — элемент с фокусом ввода.
Идентификатор строки не равен её номеру НомерСтроки и не равен индексу. Удалили строку 3 — у строк 4, 5, 6 индексы сдвинулись, а идентификаторы остались прежними. На этом и держится надёжное позиционирование.
Чтение данных из выделенной строки таблицы
Через ТекущиеДанные: на клиенте
Самый короткий путь. Подходит для обработчиков команд и событий на клиенте:
&НаКлиенте
Процедура ПоказатьЦену(Команда)
ТекДанные = Элементы.Товары.ТекущиеДанные;
Если ТекДанные = Неопределено Тогда
Сообщить("Выберите строку в таблице");
Возврат;
КонецЕсли;
Сообщить(СтрШаблон("%1: %2 руб.", ТекДанные.Номенклатура, ТекДанные.Цена));
КонецПроцедуры
Через ТекДанные можно и изменить поле: ТекДанные.Количество = 10;. Значение сразу попадёт в реквизит формы.
Через идентификатор: на сервере
ТекущиеДанные на сервере недоступны. Если обработку строки нужно выполнить на сервере (запрос к базе, расчёт по регистрам), передавайте туда идентификатор:
&НаКлиенте
Процедура ПересчитатьСтроку(Команда)
Ид = Элементы.Товары.ТекущаяСтрока;
Если Ид = Неопределено Тогда
Возврат;
КонецЕсли;
ПересчитатьСтрокуНаСервере(Ид);
КонецПроцедуры
&НаСервере
Процедура ПересчитатьСтрокуНаСервере(Ид)
Строка = Объект.Товары.НайтиПоИдентификатору(Ид);
Если Строка = Неопределено Тогда
Возврат;
КонецЕсли;
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецПроцедуры
Число передаётся между клиентом и сервером дёшево. Не таскайте на сервер всю табличную часть ради одной строки, если можно обойтись идентификатором и контекстным серверным вызовом.
Несколько выделенных строк
Включите у таблицы режим выделения «Множественный» в свойствах элемента. Дальше перебирайте массив:
&НаКлиенте
Процедура ОбнулитьСкидку(Команда)
Для Каждого Ид Из Элементы.Товары.ВыделенныеСтроки Цикл
Строка = Объект.Товары.НайтиПоИдентификатору(Ид);
Если Строка <> Неопределено Тогда
Строка.ПроцентСкидки = 0;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Как установить текущую строку программно
Табличная часть и таблица значений
Записывайте в свойство идентификатор, полученный методом ПолучитьИдентификатор() строки:
&НаКлиенте
Процедура ДобавитьУслугу(Команда)
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Количество = 1;
Элементы.Товары.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();
ТекущийЭлемент = Элементы.Товары;
Элементы.Товары.ТекущийЭлемент = Элементы.ТоварыНоменклатура;
Элементы.Товары.ИзменитьСтроку();
КонецПроцедуры
Что делает каждая строка:
Добавить()— создаёт строку в данных.ТекущаяСтрока = ...— ставит на неё курсор.ТекущийЭлемент = Элементы.Товары— переводит фокус ввода на таблицу. Без этого курсор встанет, но пользователь будет печатать в другом поле.Элементы.Товары.ТекущийЭлемент— выбирает колонку. Имя колонки берите из дерева элементов формы, у вас оно может быть другим.ИзменитьСтроку()— открывает ячейку на редактирование.
Найти строку по значению и встать на неё
Частая задача: «покажи строку с этим товаром». Ищем методом НайтиСтроки и берём первую найденную:
&НаКлиенте
Процедура ПерейтиКТовару(Номенклатура)
Отбор = Новый Структура("Номенклатура", Номенклатура);
Найденные = Объект.Товары.НайтиСтроки(Отбор);
Если Найденные.Количество() > 0 Тогда
Элементы.Товары.ТекущаяСтрока = Найденные[0].ПолучитьИдентификатор();
КонецЕсли;
КонецПроцедуры
Динамический список
Здесь в ТекущаяСтрока пишется ссылка. Обычно это делают при открытии формы списка, чтобы сразу показать нужный элемент:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если ЗначениеЗаполнено(Параметры.ТекущаяСтрока) Тогда
Элементы.Список.ТекущаяСтрока = Параметры.ТекущаяСтрока;
КонецЕсли;
КонецПроцедуры
Параметр ТекущаяСтрока есть у стандартных форм списка и выбора, поэтому из кода открытия формы его можно передать так: ОткрытьФорму("Справочник.Номенклатура.ФормаСписка", Новый Структура("ТекущаяСтрока", Ссылка)).
Если на списке стоит отбор, а нужный элемент под него не попадает, курсор на него не встанет. Сначала проверьте отборы и иерархию: в иерархическом списке элемент может лежать в другой группе.
Обычная форма
В толстом клиенте с обычными формами присваивается сама строка, без идентификаторов:
НоваяСтрока = Товары.Добавить();
ЭлементыФормы.Товары.ТекущаяСтрока = НоваяСтрока;
Этот код в управляемой форме не сработает: там нет коллекции ЭлементыФормы, а в свойство нужно писать число.
Первая и последняя строка: навигация по списку
Для табличной части и таблицы значений крайние строки берутся по индексу. Перед обращением обязательно проверяйте количество, иначе пустая таблица даст ошибку выхода индекса за границы.
&НаКлиенте
Процедура ВПервуюСтроку(Команда)
Если Объект.Товары.Количество() > 0 Тогда
Элементы.Товары.ТекущаяСтрока = Объект.Товары[0].ПолучитьИдентификатор();
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВПоследнююСтроку(Команда)
Всего = Объект.Товары.Количество();
Если Всего > 0 Тогда
Элементы.Товары.ТекущаяСтрока = Объект.Товары[Всего - 1].ПолучитьИдентификатор();
КонецЕсли;
КонецПроцедуры
Переход на соседнюю строку — через индекс текущей:
&НаКлиенте
Процедура СледующаяСтрока(Команда)
Ид = Элементы.Товары.ТекущаяСтрока;
Если Ид = Неопределено Тогда
Возврат;
КонецЕсли;
Строка = Объект.Товары.НайтиПоИдентификатору(Ид);
Индекс = Объект.Товары.Индекс(Строка);
Если Индекс < Объект.Товары.Количество() - 1 Тогда
Элементы.Товары.ТекущаяСтрока = Объект.Товары[Индекс + 1].ПолучитьИдентификатор();
КонецЕсли;
КонецПроцедуры
Помните: индекс — это порядок строк в данных. Если пользователь отсортировал таблицу кликом по заголовку колонки, на экране порядок другой, и «следующая» по индексу может оказаться не той, что видна ниже.
В динамическом списке индексов нет: строки подгружаются порциями с сервера. Чтобы встать на «первый» или «последний» элемент, найдите его ссылку запросом с ПЕРВЫЕ 1 и нужной сортировкой, затем присвойте ссылку в ТекущаяСтрока. Сортировка запроса должна совпадать с сортировкой списка, иначе «первый» в запросе и на экране разойдутся.
Событие ПриАктивизацииСтроки и смена выделения
Когда пользователь перемещает курсор, у таблицы срабатывает событие ПриАктивизацииСтроки. Его используют, чтобы обновить подчинённую таблицу, картинку товара или подсказку внизу формы.
&НаКлиенте
Процедура ТоварыПриАктивизацииСтроки(Элемент)
ТекДанные = Элемент.ТекущиеДанные;
Если ТекДанные = Неопределено Тогда
Возврат;
КонецЕсли;
ПодсказкаПоСтроке = СтрШаблон("Остаток на складе уточняется для: %1", ТекДанные.Номенклатура);
КонецПроцедуры
Не вызывайте сервер при каждом движении курсора
Пользователь листает список стрелкой вниз и проходит 30 строк за пару секунд. Если в обработчике стоит серверный вызов, это 30 вызовов и подтормаживание формы. Отложите работу через обработчик ожидания:
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
ОтключитьОбработчикОжидания("ОбновитьДетали");
ПодключитьОбработчикОжидания("ОбновитьДетали", 0.3, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьДетали()
ТекСсылка = Элементы.Список.ТекущаяСтрока;
Если ТекСсылка <> Неопределено Тогда
ОбновитьДеталиНаСервере(ТекСсылка);
КонецЕсли;
КонецПроцедуры
Третий параметр Истина означает однократный вызов. Сервер дёрнется один раз, когда пользователь остановится на строке. Процедура, указанная в обработчике ожидания, должна быть клиентской и без параметров.
Для динамического списка платформа и сама откладывает ПриАктивизацииСтроки на небольшую паузу. Но если внутри тяжёлый запрос, свой обработчик ожидания всё равно полезен: им вы управляете задержкой явно.
Ошибки при работе с текущей строкой
Вернуть курсор на место после такой пересборки можно так. Запоминаем товар до вызова, ищем его после:
&НаКлиенте
Процедура ЗаполнитьЦены(Команда)
ТекДанные = Элементы.Товары.ТекущиеДанные;
Запомненный = ?(ТекДанные = Неопределено, Неопределено, ТекДанные.Номенклатура);
ЗаполнитьЦеныНаСервере();
Если Запомненный <> Неопределено Тогда
Найденные = Объект.Товары.НайтиСтроки(Новый Структура("Номенклатура", Запомненный));
Если Найденные.Количество() > 0 Тогда
Элементы.Товары.ТекущаяСтрока = Найденные[0].ПолучитьИдентификатор();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Если один товар встречается в нескольких строках, запоминайте пару «товар + номер строки» или другое поле, которое однозначно определяет строку.
Ещё одна тихая ошибка — запомнить в переменную ТекДанные, вызвать сервер и потом писать в эту переменную. После контекстного серверного вызова данные формы на клиенте обновляются, и старая ссылка на строку может указывать уже не туда. Безопаснее после вызова заново взять Элементы.Товары.ТекущиеДанные.
Управляемые формы против обычных: что изменилось
Код из старых конфигураций на обычных формах часто переносят копированием, и он ломается. Сводка различий:
| Что делаем | Обычная форма | Управляемая форма |
|---|---|---|
| Обращение к элементу | ЭлементыФормы.Товары | Элементы.Товары |
| Значение ТекущаяСтрока | Строка коллекции | Идентификатор (число), для списка — ссылка |
| Получить строку | Сразу из ТекущаяСтрока | НайтиПоИдентификатору(Ид) |
| Где доступны данные строки | Везде, форма живёт в толстом клиенте | ТекущиеДанные — на клиенте, идентификатор — и на сервере |
| Событие смены строки | ПриАктивизацииСтроки | ПриАктивизацииСтроки (клиентское) |
Ещё три особенности управляемых форм, о которых стоит помнить:
- 🔒 Если таблица в режиме «только просмотр», курсор ставится как обычно, но редактировать строку пользователь не сможет — вызов
ИзменитьСтроку()тут бесполезен. - 🌳 В дереве значений поиск по идентификатору работает по всем уровням:
НайтиПоИдентификаторунайдёт и вложенную строку. Чтобы её стало видно, родителя нужно развернуть методомРазвернутьэлемента-таблицы. - 🔁 Установка
ТекущаяСтрокавПриСозданииНаСервереработает и для табличных частей, и для списков. Удобно, когда форма открывается «с позиционированием» по переданному параметру.
Если вы дорабатываете типовую конфигурацию , вносите такие обработчики через расширение конфигурации , а не правкой основной конфигурации. Так изменения переживут обновление релиза.
Частые вопросы
Можно ли узнать номер строки, на которой стоит курсор?
НайтиПоИдентификатору, затем возьмите поле НомерСтроки (для табличной части) или индекс методом Индекс(). Номер считается с 1, индекс — с 0.Почему ТекущаяСтрока в динамическом списке возвращает ссылку, а не число?
Как снять выделение со всех строк?
Элементы.Товары.ВыделенныеСтроки.Очистить(). Текущая строка при этом может остаться, это отдельное свойство.Сохраняется ли текущая строка при закрытии и открытии формы?
ПриСозданииНаСервере или ПриОткрытии.Можно ли поставить курсор на строку, скрытую отбором строк таблицы?
ОтборСтрок = Неопределено), затем установите текущую строку.