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