Почему в динамическом списке 1С с произвольным запросом не работают ENTER и DEL и как это исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов на управляемых формах в 1С:Предприятие 8 одним из самых популярных инструментов вывода данных является динамический список. Он удобен, быстр и позволяет гибко настраивать отображение информации. Однако разработчики часто сталкиваются с неприятной особенностью: как только в свойствах списка взводится флаг «Произвольный запрос», стандартное поведение интерфейса ломается. Пользователи теряют возможность открывать элементы по клавише ENTER (или двойным кликом мыши), а также помечать элементы на удаление по клавише DEL.

В рамках этой статьи мы подробно разберем, почему возникает эта проблема, где в интерфейсе конфигуратора скрывается нужная настройка и как программно обойти данное ограничение, если ваш запрос слишком сложен и стандартные механизмы платформы не справляются.


Выясняем причину: почему пропадают функции ENTER, DEL и другие действия?

Когда динамический список работает в стандартном режиме (выбирает данные напрямую из таблицы справочника или документа без использования произвольного запроса), платформа 1С четко понимает контекст данных. Ей известно, какая именно таблица базы данных выступает источником. На основании этого знания система автоматически генерирует стандартные команды управления: создание нового элемента, копирование, удаление, пометка на удаление и открытие формы объекта.

Как только мы включаем признак «Произвольный запрос» и начинаем описывать логику получения данных самостоятельно, платформа временно теряет эту жесткую связь. Даже если в тексте запроса вы выбираете поле Ссылка, для платформы это всего лишь одно из полей выборки. Без явного указания метаданных система не может гарантировать, что выбранная строка однозначно сопоставляется с конкретным объектом базы данных.

В результате происходят следующие изменения:


Решение 1: Указание основной таблицы в конфигураторе

Самый простой и правильный способ вернуть стандартный функционал — явно указать свойство ОсновнаяТаблица в настройках динамического списка. Многие начинающие разработчики совершают ошибку: они ищут это свойство в стандартной палитре свойств реквизита формы (справа в конфигураторе) и не находят его там после установки флага «Произвольный запрос».

Давайте разберем по шагам, где на самом деле находится эта настройка:

  1. Откройте управляемую форму, на которой расположен ваш динамический список.
  2. Перейдите на вкладку «Реквизиты» (в правом верхнем углу редактора формы).
  3. Найдите ваш реквизит с типом ДинамическийСписок и дважды кликните по нему (или нажмите правой кнопкой мыши и выберите «Свойства»).
  4. В палитре свойств найдите строку «Настройка списка» и нажмите по гиперссылке «Открыть».
  5. Перед вами откроется окно конструктора динамического списка. Обратите внимание на нижнюю часть этого окна — прямо под текстовым полем ввода запроса находится поле «Основная таблица».
  6. Нажмите кнопку выбора в этом поле и укажите нужную таблицу (например, Справочник.СписокФайлов).
  7. Нажмите кнопку «ОК» для сохранения настроек.

После выполнения этих простых действий платформа снова свяжет строки списка с метаданными выбранного справочника или документа. Клавиши ENTER, DEL, Insert и кнопки командной панели вернутся к своему стандартному поведению.


Решение 2: Программный обход, если основную таблицу указать невозможно

Бывают ситуации, когда логика работы интерфейса требует объединения данных из абсолютно разных таблиц (например, с помощью оператора ОБЪЕДИНИТЬ) или вывода информации, не имеющей прямой привязки к конкретному объекту метаданных. В таких сценариях указать одну основную таблицу физически невозможно. Нам придется реализовать обработку клавиш ENTER, DEL и Insert вручную через программный код управляемой формы.

Рассмотрим подробнее реализацию каждого действия.

Программная замена клавиши ENTER (открытие формы элемента)

Для того чтобы при нажатии клавиши ENTER или при двойном клике мыши открывалась форма нужного нам объекта, мы должны перехватить стандартное событие таблицы формы Выбор.

Создадим на клиенте обработчик этого события и напишем следующий код:


&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    
    // Отменяем стандартное поведение системы
    СтандартнаяОбработка = Ложь;
    
    // Получаем данные текущей строки списка
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    
    Если ТекущиеДанные <> Неопределено Тогда
        // Проверяем, заполнена ли ссылка на объект
        Если ЗначениеЗаполнено(ТекущиеДанные.Ссылка) Тогда
            // Программное открытие формы выбранного объекта
            ПараметрыОткрытия = Новый Структура("Ключ", ТекущиеДанные.Ссылка);
            ОткрытьФорму("Справочник.СписокФайлов.ФормаОбъекта", ПараметрыОткрытия);
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Программная замена клавиши DEL (пометка на удаление)

Для реализации пометки удаления при нажатии на DEL используется обработчик события таблицы формы ПередУдалением. Здесь нам потребуется переслать вызов на сервер, чтобы безопасно изменить состояние объекта в базе данных.

Схема реализации выглядит следующим образом:


&НаКлиенте
Процедура СписокПередУдалением(Элемент, Отказ)
    
    // Отменяем стандартное удаление платформы
    Отказ = Истина;
    
    ТекущиеДанные = Элементы.Список.ТекущиеДанные;
    
    Если ТекущиеДанные <> Неопределено И ЗначениеЗаполнено(ТекущиеДанные.Ссылка) Тогда
        
        // Запрашиваем подтверждение у пользователя (хороший тон проектирования UI)
        ОписаниеОповещения = Новый ОписаниеОповещения("ВыполнитьПометкуУдаленияЗавершение", ЭтотОбъект, ТекущиеДанные.Ссылка);
        ПоказатьВопрос(ОписаниеОповещения, "Изменить пометку удаления для выбранного элемента?", РежимДиалогаВопрос.ДаНет);
        
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьПометкуУдаленияЗавершение(РезультатВопроса, ДополнительныеПараметры) Экспорт
    
    Если РезультатВопроса = КодВозвратаДиалога.Да Тогда
        СсылкаНаОбъект = ДополнительныеПараметры;
        // Вызываем серверный контекст для изменения объекта
        УстановитьПометкуНаСервере(СсылкаНаОбъект);
        // Принудительно обновляем наш список на клиенте
        Элементы.Список.Обновить();
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Процедура УстановитьПометкуНаСервере(СсылкаНаОбъект)
    
    // Получаем объект, меняем пометку удаления на противоположную и записываем
    ОбъектБазы = СсылкаНаОбъект.ПолучитьОбъект();
    Если ОбъектБазы <> Неопределено Тогда
        НовоеЗначениеПометки = Не ОбъектБазы.ПометкаУдаления;
        ОбъектБазы.УстановитьПометкуУдаления(НовоеЗначениеПометки);
    КонецЕсли;
    
КонецПроцедуры

Программная замена клавиши Insert (создание нового элемента)

Аналогичным образом мы можем перехватить попытку добавления нового элемента в список через клавишу Insert или кнопку командной панели «Создать». Для этого используется событие таблицы ПередДобавлением:


&НаКлиенте
Процедура СписокПередДобавлением(Элемент, Отказ, Копирование, Родитель, Группа, НовыйСтрока)
    
    // Отменяем стандартное создание
    Отказ = Истина;
    
    ПараметрыФормы = Новый Структура;
    
    // Если происходило копирование, передаем ссылку копируемого объекта в параметры
    Если Копирование И Элементы.Список.ТекущиеДанные <> Неопределено Тогда
        ПараметрыФормы.Вставить("ЗначениеКопирования", Элементы.Список.ТекущиеДанные.Ссылка);
    КонецЕсли;
    
    // Открываем форму для создания нового элемента
    ОткрытьФорму("Справочник.СписокФайлов.ФормаОбъекта", ПараметрыФормы, Элемент);
    
КонецПроцедуры

Дополнительный совет: Использование пакетных запросов для сложных выборок

Программисты часто отказываются от указания основной таблицы из-за необходимости связывать данные с тяжелыми виртуальными таблицами или выполнять сложные расчеты непосредственно внутри динамического списка. Но написание ручных обработчиков событий формы под каждую стандартную кнопку существенно увеличивает объем кода и усложняет дальнейшую поддержку конфигурации.

Существует альтернативный архитектурный паттерн — использование пакетных запросов внутри динамического списка. Рассмотрим этот подход подробнее:

  1. В первой части пакета запросов вы подготавливаете сложные данные, связываете таблицы, накладываете специфические фильтры и помещаете промежуточный результат во временную таблицу (ВТ) (например, ВТ_ДополнительныеДанные).
  2. Во втором (последнем) запросе пакета вы делаете выборку из вашей основной таблицы справочника и связываете её через ЛЕВОЕ СОЕДИНЕНИЕ с созданной временной таблицей ВТ_ДополнительныеДанные по полю Ссылка.
  3. Поскольку последняя выборка пакета производится из физической таблицы справочника, платформа 1С позволит вам без проблем указать это свойство в поле «Основная таблица».

Таким образом, вы убиваете двух зайцев сразу: сохраняете высокую производительность за счет правильного индексирования временных таблиц и оставляете весь стандартный интерфейсный функционал (работа клавиш DEL, ENTER, сортировка по колонкам и быстрый поиск) без написания строчки программного кода.

Важное примечание для разработчиков в среде EDT (Enterprise Development Tools): При написании пакетных запросов в динамических списках избегайте использования инструкции УНИЧТОЖИТЬ ВТ_ДополнительныеДанные в конце пакета. Из-за особенностей синтаксического анализатора EDT автоматическое определение основной таблицы может сбоить. Платформа 1С самостоятельно и корректно уничтожит все временные таблицы после выполнения запроса динамического списка на сервере.


Резюме

Мы проанализировали особенности работы динамических списков в управляемых формах 1С и выяснили, что:

← На главную