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