При разработке интерфейсов на управляемых формах 1С часто возникает задача: отобразить сложные данные из нескольких источников в виде единого списка и при этом иметь возможность программно спозиционировать курсор на конкретном документе или элементе справочника. Однако если динамический список использует произвольный запрос без указания Основной таблицы, стандартное присвоение ссылки в свойство ТекущаяСтрока не срабатывает. Разберем причины такого поведения платформы и рассмотрим рабочие способы решения этой задачи.
Выясним причину проблемы. Когда у динамического списка задана Основная таблица, платформа точно знает тип ключевого поля (например, ДокументСсылка.ЗаказКлиента) и использует его в качестве идентификатора строки. В этом случае для позиционирования достаточно выполнить код вида Элементы.Список.ТекущаяСтрока = НужнаяСсылка;.
Если же запрос объединяет несколько таблиц и основная таблица не выбрана, свойство ТекущаяСтрока таблицы формы принимает целочисленное значение (числовой индекс записи в клиентской выборке). Напрямую передать туда ссылку нельзя. Кроме того, динамический список считывает данные порциями: на стороне клиента физически нет полного массива строк, поэтому найти индекс произвольной ссылки стандартными методами клиента невозможно (метод НайтиПоИдентификатору() доступен только для коллекций данных формы, таких как ТаблицаЗначений).
Рассмотрим рабочий способ позиционирования курсора без изменения структуры метаданных. Идея заключается в том, чтобы на сервере программно получить исполняемую схему и настройки динамического списка, сформировать результат в коллекцию значений, найти порядковый номер строки с нужной ссылкой и передать этот индекс на клиент.
Разберем по шагам реализацию этого механизма в модуле управляемой формы:
&НаСервере
Функция СтрокиДСНаСервере(ТекДок)
// Получаем текущую схему и пользовательские настройки динамического списка
Схема = ЭтаФорма.Элементы.Заказы.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
Настройки = ЭтаФорма.Элементы.Заказы.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
СтрокиДС = ПроцессорВывода.Вывести(ПроцессорКомпоновки);
ТекСтр = Неопределено;
// Ищем строку с целевой ссылкой и определяем её индекс
Для Каждого Стр Из СтрокиДС Цикл
Если Стр.Заказ = ТекДок Тогда
ТекСтр = СтрокиДС.Индекс(Стр);
Прервать;
КонецЕсли;
КонецЦикла;
Возврат ТекСтр;
КонецФункции
&НаКлиенте
Процедура ДСУстановитьТекСтр(ТекСсылка)
Если Не ЗначениеЗаполнено(ТекСсылка) Тогда
Возврат;
КонецЕсли;
ТекСтр = СтрокиДСНаСервере(ТекСсылка);
Если ТекСтр = Неопределено Тогда
Возврат;
КонецЕсли;
// Устанавливаем позицию в таблице формы (с учетом смещения индексации)
ЭтаФорма.Элементы.Заказы.ТекущаяСтрока = ТекСтр + 1;
КонецПроцедуры
Проанализируем важные особенности и ограничения этого подхода:
Если динамический список объединяет документы разных видов (например, ЗаказПокупателя, ЗаказПоставщику, СчетНаОплату), более надежным архитектурным решением является создание объекта метаданных Журнал документов.
Посмотрим на преимущества этого варианта:
Основной таблицы динамического списка.ТекущаяСтрока снова начнет принимать стандартные ссылки любого из входящих в журнал документов без необходимости писать серверный код поиска по индексам.Когда требуется объединять не только документы, но и другие типы данных (например, элементы справочников, регистры или внешние идентификаторы), данные можно агрегировать в периодическом или непериодическом регистре сведений.
В этом случае регистр сведений задается в качестве основной таблицы динамического списка, а позиционирование строки выполняется через ключ записи:
КлючЗаписи = РегистрыСведений.ОчередьОбработки.СоздатьКлючЗаписи(Новый Структура("Документ, Идентификатор", СсылкаНаОбъект, УникальныйИД));
Элементы.Список.ТекущаяСтрока = КлючЗаписи;
Если объем выводимых данных небольшой (до нескольких тысяч строк), динамический список целесообразно заменить на реквизит формы с типом ТаблицаЗначений. В этом сценарии:
ДанныеФормыКоллекция.НайтиСтроки() на сервере или клиенте.Элементы.Таблица.ТекущаяСтрока = НайденнаяСтрока.ПолучитьИдентификатор();.Если единственная цель перехода к строке — показать пользователю конкретную запись, можно применить фильтрацию. При установке отбора по ссылке динамический список оставит на экране только искомую запись, избавив от необходимости искать числовой индекс:
&НаКлиенте
Процедура ОтобратьПоСсылке(ЦелеваяСсылка)
ЭлементОтбора = Неопределено;
Для Каждого Элемент Из Список.Отбор.Элементы Цикл
Если Элемент.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Заказ") Тогда
ЭлементОтбора = Элемент;
Прервать;
КонецЕсли;
КонецЦикла;
Если ЭлементОтбора = Неопределено Тогда
ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Заказ");
КонецЕсли;
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = ЦелеваяСсылка;
ЭлементОтбора.Использование = Истина;
КонецПроцедуры