При разработке интерфейсов на управляемых формах в 1С:Предприятие 8 одним из самых популярных инструментов вывода данных является динамический список. Он удобен, быстр и позволяет гибко настраивать отображение информации. Однако разработчики часто сталкиваются с неприятной особенностью: как только в свойствах списка взводится флаг «Произвольный запрос», стандартное поведение интерфейса ломается. Пользователи теряют возможность открывать элементы по клавише ENTER (или двойным кликом мыши), а также помечать элементы на удаление по клавише DEL.
В рамках этой статьи мы подробно разберем, почему возникает эта проблема, где в интерфейсе конфигуратора скрывается нужная настройка и как программно обойти данное ограничение, если ваш запрос слишком сложен и стандартные механизмы платформы не справляются.
Когда динамический список работает в стандартном режиме (выбирает данные напрямую из таблицы справочника или документа без использования произвольного запроса), платформа 1С четко понимает контекст данных. Ей известно, какая именно таблица базы данных выступает источником. На основании этого знания система автоматически генерирует стандартные команды управления: создание нового элемента, копирование, удаление, пометка на удаление и открытие формы объекта.
Как только мы включаем признак «Произвольный запрос» и начинаем описывать логику получения данных самостоятельно, платформа временно теряет эту жесткую связь. Даже если в тексте запроса вы выбираете поле Ссылка, для платформы это всего лишь одно из полей выборки. Без явного указания метаданных система не может гарантировать, что выбранная строка однозначно сопоставляется с конкретным объектом базы данных.
В результате происходят следующие изменения:
ENTER или двойном клике, и какой объект помечать на удаление по кнопке DEL.Самый простой и правильный способ вернуть стандартный функционал — явно указать свойство ОсновнаяТаблица в настройках динамического списка. Многие начинающие разработчики совершают ошибку: они ищут это свойство в стандартной палитре свойств реквизита формы (справа в конфигураторе) и не находят его там после установки флага «Произвольный запрос».
Давайте разберем по шагам, где на самом деле находится эта настройка:
ДинамическийСписок и дважды кликните по нему (или нажмите правой кнопкой мыши и выберите «Свойства»).Справочник.СписокФайлов).После выполнения этих простых действий платформа снова свяжет строки списка с метаданными выбранного справочника или документа. Клавиши ENTER, DEL, Insert и кнопки командной панели вернутся к своему стандартному поведению.
Бывают ситуации, когда логика работы интерфейса требует объединения данных из абсолютно разных таблиц (например, с помощью оператора ОБЪЕДИНИТЬ) или вывода информации, не имеющей прямой привязки к конкретному объекту метаданных. В таких сценариях указать одну основную таблицу физически невозможно. Нам придется реализовать обработку клавиш ENTER, DEL и Insert вручную через программный код управляемой формы.
Рассмотрим подробнее реализацию каждого действия.
Для того чтобы при нажатии клавиши ENTER или при двойном клике мыши открывалась форма нужного нам объекта, мы должны перехватить стандартное событие таблицы формы Выбор.
Создадим на клиенте обработчик этого события и напишем следующий код:
&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
// Отменяем стандартное поведение системы
СтандартнаяОбработка = Ложь;
// Получаем данные текущей строки списка
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// Проверяем, заполнена ли ссылка на объект
Если ЗначениеЗаполнено(ТекущиеДанные.Ссылка) Тогда
// Программное открытие формы выбранного объекта
ПараметрыОткрытия = Новый Структура("Ключ", ТекущиеДанные.Ссылка);
ОткрытьФорму("Справочник.СписокФайлов.ФормаОбъекта", ПараметрыОткрытия);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Для реализации пометки удаления при нажатии на DEL используется обработчик события таблицы формы ПередУдалением. Здесь нам потребуется переслать вызов на сервер, чтобы безопасно изменить состояние объекта в базе данных.
Схема реализации выглядит следующим образом:
&НаКлиенте
Процедура СписокПередУдалением(Элемент, Отказ)
// Отменяем стандартное удаление платформы
Отказ = Истина;
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено И ЗначениеЗаполнено(ТекущиеДанные.Ссылка) Тогда
// Запрашиваем подтверждение у пользователя (хороший тон проектирования UI)
ОписаниеОповещения = Новый ОписаниеОповещения("ВыполнитьПометкуУдаленияЗавершение", ЭтотОбъект, ТекущиеДанные.Ссылка);
ПоказатьВопрос(ОписаниеОповещения, "Изменить пометку удаления для выбранного элемента?", РежимДиалогаВопрос.ДаНет);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьПометкуУдаленияЗавершение(РезультатВопроса, ДополнительныеПараметры) Экспорт
Если РезультатВопроса = КодВозвратаДиалога.Да Тогда
СсылкаНаОбъект = ДополнительныеПараметры;
// Вызываем серверный контекст для изменения объекта
УстановитьПометкуНаСервере(СсылкаНаОбъект);
// Принудительно обновляем наш список на клиенте
Элементы.Список.Обновить();
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура УстановитьПометкуНаСервере(СсылкаНаОбъект)
// Получаем объект, меняем пометку удаления на противоположную и записываем
ОбъектБазы = СсылкаНаОбъект.ПолучитьОбъект();
Если ОбъектБазы <> Неопределено Тогда
НовоеЗначениеПометки = Не ОбъектБазы.ПометкаУдаления;
ОбъектБазы.УстановитьПометкуУдаления(НовоеЗначениеПометки);
КонецЕсли;
КонецПроцедуры
Аналогичным образом мы можем перехватить попытку добавления нового элемента в список через клавишу Insert или кнопку командной панели «Создать». Для этого используется событие таблицы ПередДобавлением:
&НаКлиенте
Процедура СписокПередДобавлением(Элемент, Отказ, Копирование, Родитель, Группа, НовыйСтрока)
// Отменяем стандартное создание
Отказ = Истина;
ПараметрыФормы = Новый Структура;
// Если происходило копирование, передаем ссылку копируемого объекта в параметры
Если Копирование И Элементы.Список.ТекущиеДанные <> Неопределено Тогда
ПараметрыФормы.Вставить("ЗначениеКопирования", Элементы.Список.ТекущиеДанные.Ссылка);
КонецЕсли;
// Открываем форму для создания нового элемента
ОткрытьФорму("Справочник.СписокФайлов.ФормаОбъекта", ПараметрыФормы, Элемент);
КонецПроцедуры
Программисты часто отказываются от указания основной таблицы из-за необходимости связывать данные с тяжелыми виртуальными таблицами или выполнять сложные расчеты непосредственно внутри динамического списка. Но написание ручных обработчиков событий формы под каждую стандартную кнопку существенно увеличивает объем кода и усложняет дальнейшую поддержку конфигурации.
Существует альтернативный архитектурный паттерн — использование пакетных запросов внутри динамического списка. Рассмотрим этот подход подробнее:
ВТ_ДополнительныеДанные).ЛЕВОЕ СОЕДИНЕНИЕ с созданной временной таблицей ВТ_ДополнительныеДанные по полю Ссылка.Таким образом, вы убиваете двух зайцев сразу: сохраняете высокую производительность за счет правильного индексирования временных таблиц и оставляете весь стандартный интерфейсный функционал (работа клавиш DEL, ENTER, сортировка по колонкам и быстрый поиск) без написания строчки программного кода.
Важное примечание для разработчиков в среде EDT (Enterprise Development Tools): При написании пакетных запросов в динамических списках избегайте использования инструкции УНИЧТОЖИТЬ ВТ_ДополнительныеДанные в конце пакета. Из-за особенностей синтаксического анализатора EDT автоматическое определение основной таблицы может сбоить. Платформа 1С самостоятельно и корректно уничтожит все временные таблицы после выполнения запроса динамического списка на сервере.
Мы проанализировали особенности работы динамических списков в управляемых формах 1С и выяснили, что:
ОсновнаяТаблица.СтандартнаяОбработка = Ложь.